概述
Arguments 对象已经不再是函数的属性了, 它是函数内部的本地变量, 包括如下属性:
- callee — 指向当前函数的引用
- length — 真正传递的参数个数
- properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。 properties-indexes内部元素的个数等于arguments.length. properties-indexes 的值和实际传递进来的参数之间是共享的。
Demo
arguments.callee
我们可以利用 callee 引用来写几个常见的递归, 如下:
//求阶乘n! 即,1x2x3x4x5x......xn
function n(i){
return i < 2 ? 1 : i*arguments.callee(i-1);
}
//求1+2+3......+n
function p(i){
return i < 2 ? 1 : i+arguments.callee(i-1);
}
//斐波那契数列, 1,1,2,3,5,8,13,......
function f(i){
var _f = arguments.callee;
return i < 3 ? 1 : _f(i-1) + _f(i-2);
}
n(5);//120
p(5);//15
f(5);//5
遗憾的是: 严格模式(“use strict“)下, arguments.callee 并不可用.
arguments.length
js方法中形参个数并不能实际反映实参个数, 所幸的是 arguments.length 可以取得实参个数, 如下:
function a(a,b,c){
console.log('实参个数:' + arguments.length);
}
a(1,2);//实参个数:2
arguments[]
这个共享其实不是真正的共享一个内存地址,而是2个不同的内存地址,使用JavaScript引擎来保证2个值是随时一样的,当然这也有一个前提, 那就是这个索引值要小于你传入的参数个数,也就是说如果你只传入2个参数,而还继续使用arguments[2]赋值的话,就会不一致(索引值从 0 开始),例如:
function b(x, y, z) {
arguments[2] = 10;//参数可以被重新赋值
console.log(z);
}
b(1, 2);//undefined
这时候因为没传递第三个参数z,所以赋值10以后,console.log(z)的结果依然是undefined,而不是10.
鸭式辩型
arguments
对象并不是一个真正的Array
。它类似于数组,但没有数组所特有的属性和方法,除了 length。例如,它没有 pop 方法。不过可以将其转换成数组.
var args = Array.prototype.slice.call(arguments);//args为数组
像上面这中arguments虽然不是数组, 但我们把它当做数组处理, 这种现象叫做 鸭式辩型
.
如果一个对象可以像鸭子一样走路,游泳,并且嘎嘎叫,就认为这个对象是鸭子,哪怕它并不是从鸭子对象继承过来的。
在javascript里面,很多函数都不做对象的类型检测,而是只关心这些对象能做什么. 因此我们尽可利用鸭式辨型的便利, 以下就充分演示了把arguments当做一个数组来处理.
//合并参数
function myConcat(separator) {
var args = Array.prototype.slice.call(arguments, 1);//相当于arguments调用了Array的slice方法
return args.join(separator);
}
myConcat(", ", "red", "orange", "blue");//"red, orange, blue"
警告: 此处不应在 arguments 对象上使用 slice 方法,这会阻碍 JavaScript 引擎的优化 (比如 V8 引擎)。作为替代,应通过遍历 arguments 对象的方式来构建一个新的数组。更多信息。
如果 Array generics 可用的话,下面的代码则可以作为替代:
var args = Array.slice(arguments);//注意,arguments对象仅在函数内部有效
本文就讨论这么多内容,大家有什么问题或好的想法欢迎在下方参与留言和评论.
本文作者: louis
本文链接: http://louiszhai.github.io/2015/12/15/arguments/
参考文章