MDN解释:arguments
是一个对应于传递给函数的参数的类数组对象。
arguments的使用
当我们不确定有多少个参数传递的时候,可以用arguments来获取。在js中,arguments实际上是当前函数的一个内置对象。所有的函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参。具体使用格式如下
function func1(a, b, c) { console.log(arguments[0]); // 1 console.log(arguments[1]); // 2 console.log(arguments[2]); // 3 } func1(1, 2, 3);
实际上,arguments
对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments
对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处
此外,arguments展示的形式是一个伪数组(类数组对象),因此可以进行遍历。伪数组具有一下特点:
- 具有length属性
- 按索引方式存储数据
- 不具有数组的push、pop等方法
但是它可以被转换为一个真正的Array
var args = Array.prototype.slice.call(arguments); var args = [].slice.call(arguments);
最后,arguments对象其实还有一个callee属性,是一个指向arguments对象所在函数的指针
function foo() { console.log(arguments.callee === foo);//true } foo(5);
例子
1、遍历参数求和
function add() { var sum =0, len = arguments.length; for(var i=0; i<len; i++){ sum += arguments[i]; } return sum; } add() // 0 add(1) // 1 add(1,2,3,4); // 10
2、callee属性阶乘函数的例子
首先我们来看看下面的阶乘函数
function foo(num) { if(num <= 1){ return 1; }else{ return num * foo(num - 1); } }
阶乘函数一般定义成递归调用的,就像上面的这个例子一样。只要给函数一个名称,而且这个名称不会变,这样定义就没有问题。但是这个函数正确执行就必须保证函数名是foo,从而导致了紧密耦合,使用arguments.callee就可以让函数逻辑与函数名解耦:
function foo(num) { if(num <= 1){ return 1; }else{ return num * arguments.callee(num - 1); } }
这个重写后的foo()函数已经用arguments.callee代替之前硬编码的foo。这意味着无论函数叫什么名称,都可以引用正确的函数。如下:
function foo(num) { if(num <= 1){ return 1; }else{ return num * arguments.callee(num - 1); } } let trueFoo = foo; foo = function () { return 0; } console.log(trueFoo(5));//120 console.log(foo(5));//0
trueFoo变量被赋值为foo,实际上把同一个函数的指针又保存到另一个位置。然后foo函数又被重写为一个返回0的函数。如果像之前的版本不使用callee,那么象上面那样调用trueFoo就会返回0。