JS 函数(3)—arguments对象
arguments对象
JS中的参数在内部是用一个数组来表示的。函数接收到的始终是这个数组。
在函数体内能够通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。
arguments对象与数组类似,可以使用方括号语法访问它的每一个元素,但它并不是Array的实例。
arguments[0]访问第一个元素、arguments[1]访问第二个元素。。。以此类推。。。
也就是说,下面三个函数的调用结果完全一样。
示例1:
1 function sayHi (name, message) { //这是个正常的函数 2 console.log("Hello " + name + "," + message); 3 }; 4 sayHi("CC","Nice to meet you!"); //Hello CC,Nice to meet you!
示例2:
1 function sayHi (name,message) { 2 console.log("Hello " + arguments[0] + "," + arguments[1]); //用arguments对象访问参数数组 3 }; 4 sayHi("CC","Nice to meet you!"); //Hello CC,Nice to meet you!
示例3:
1 function sayHi () { //根本没有命名参数 2 console.log("Hello " + arguments[0] + "," + arguments[1]); //用arguments对象访问参数数组 3 }; 4 sayHi("CC","Nice to meet you!"); //Hello CC,Nice to meet you!
这个事实,说明了JS中函数的一个重要特点:命名参数只是提供便利,不是必需的。
arguments对象可以和命名参数一起使用。
arguments对象的值永远与对应命名参数的值保持同步;它们的内存空间是独立的,但是它们的值会同步。
arguments.length
通过访问arguments对象的length属性,可以获知有多少参数传递给了函数。
arguments对象的length值是由传入的参数的个数决定的,不是由定义函数时的命名参数的个数决定的。
示例1:根据传入的参数个数不同,利用arguments.length实现不同的功能
1 function doAdd() { 2 if(arguments.length === 1) { 3 return arguments[0] + 10; 4 } 5 if(arguments.length === 2) { 6 return arguments[0] + arguments[1] 7 } 8 } 9 console.log(doAdd(10)); //20 10 console.log(doAdd(10, 20)); //30
示例2:利用arguments.length实现参数求和
1 function add() { 2 var count = arguments.length; 3 var sum = 0; 4 for (var i=0; i<count; i++) { 5 sum += arguments[i]; 6 }; 7 return sum; 8 }; 9 add(1,2,3,4,5); //15
示例3:利用arguments.length获取参数最大值
1 function maxNum() { 2 var count = arguments.length; //获取参数的个数,保存到变量count 3 var arr = []; //创建一个空数组arr 4 for(var i=0; i<count; i++) { //遍历函数参数 5 if(arguments) { 6 arr[i] = arguments[i]; //将参数存入数组arr 7 }; 8 }; 9 10 function compare(value1,value2) { //写一个升序排列的比较函数compare 11 if(value1<value2) { 12 return -1; //升序排列,如果前面的值小于后面的值,返回负数 13 } else if(value1>value2) { 14 return 1; 15 } else { 16 return 0; 17 }; 18 }; 19 20 arr.sort(compare); //将compare传入数组的sort()方法,将数组按升序排列 21 return arr[arr.length-1] //返回数组中的最后一个值,即为最大值 22 }; 23 24 maxNum(10,50,100,70); //100
参数始终是按值传递的,不可能通过引用传递参数。
arguments.callee
arguments对象有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
递归函数是一个函数通过名字调用自身的情况下构成的,下面是一个经典的阶层函数。
1 function x(num) { 2 if(num<=1){ 3 return 1; 4 } else { 5 return num * x(num-1); 6 }; 7 }; 8 console.log(x(5)); //120 9 var y = x; 10 console.log(y(5)); //120 11 x = null; 12 console.log(y(5)); //error
报错的原因在于:函数的执行与函数名x紧紧耦合在一起;当x=null,即使变量y依然能够调用函数,但函数内部的x(num-1)却无法执行。
使用arguments.callee替代x:
1 function x(num) { 2 if(num<=1){ 3 return 1; 4 } else { 5 return num * arguments.callee(num-1); 6 }; 7 }; 8 console.log(x(5)); //120 9 var y = x; 10 console.log(y(5)); //120 11 x = null; 12 console.log(y(5)); //120
在严格模式下,使用arguments.callee会报错;可以使用命名函数表达式来达成相同的效果。
1 var factorial = function f(num){ 2 if(num<=1) { 3 return 1; 4 } else { 5 return num * f(num-1); 6 }; 7 }; 8 factorial(5); //120
注意:只能通过factorial()调用,不能通过f()调用。
函数对象的caller属性,这个属性中保存着调用当前函数的函数的引用。
1 function outer() { 2 inner(); 3 }; 4 function inner() { 5 alert(inner.caller); 6 }; 7 outer();
因为outer()调用了inner(),所以inner.caller就指向了outer()。
为了实现更松散的耦合,也可以使用arguments.callee;如下:
1 function outer() { 2 inner(); 3 }; 4 function inner() { 5 alert(arguments.callee.caller); 6 }; 7 outer();
ECMAScript还定义了arguments.caller,但在严格模式下访问会报错,即使在非严格模式下,这个值也始终是undefined。
定义这个属性是为了分清arguments.caller与函数的caller属性。

浙公网安备 33010602011771号