首先一个最大的问题是,arguments这个对象哪儿来的?也许有人会认为它是调用函数时引擎自带的一个局部变量,因为我们平时使用arguments的时候都是在函数中把它当作局部变量来使用的。事实上arguments是Function实例的属性,只是在调用时候会被作为局部变量来使用而已。这也是这个对象最吸引人的地方。在函数没有运行时我们也可以访问到它,只不过没运行时它的值是null而已。
function f(){
alert(f.arguments==arguments); //true
};
alert("arguments" in f); //true
alert(f.arguments); //null
f();
arguments这个对象的作用是保存函数在运行期间的一些参数。当我们调用函数时,传入的参数会在arguments中以拟数组方式储存。它和数组一样提供了length属性,但却没有数组的方法。因此它只是一个拟数组而不是真正的数组。不过虽然不是真正的数组,我们也依然可以让数组的方法去主动调用它,比如这样调用
function join(){
return Array.prototype.join.call(arguments);
};
alert(join("a","b","c"));
也可以把它当成数组,作为apply的参数来使用,比如一个获取最大值的函数
function max(){
return Math.max.apply(null,arguments);
};
alert(max(5,2,7));
这是它作为拟数组的性质,而这个arguments本身也有自己的性质。它的参数列表和对应的形参使用的是相同的数据地址,或者说形参就是某个arguuments参数列表项的别名。看下面代码就会明白
(function(a){
a="我主页";
alert(arguments[0]); //我主页
})("测试");
这个例子中a和arguments[0]是共用的数据地址,所以给a赋值后arguments[0]的值也会改变。接着是arguments中一个关键的属性callee。这个callee指的就是函数自身,可以用一段代码来验证。
function f(){
alert(arguments.callee===f); //true
};
f();
我们经常会在匿名函数的递归中使用callee。由于匿名函数没有变量来保存它的句柄,所以只能在运行时候通过callee来获取,以实现递归。
(function(){
console.log("我主页");
setTimeout(arguments.callee,1000);
})();
像上面这样每秒一次的慢递归,这种方法可以节省一个变量名,非常推荐使用。但是对于需要效率的递归就不建议这样使用,因为在某些引擎中对arguments处理是非常复杂的,这就会影响效率。这个问题在之前的文章“
JavaScript调用堆栈对变量访问效率有影响!?
”中有提到过。即使arguments什么都没做,只是被一个分号结束也是非常影响效率的,所以在需要高效的代码中尽量避免引入arguments。
转载请注明:前端录»JavaScript的arguments及其子对象
<script src="http://www.wozhuye.com/index.php?m=digg&c=index&a=init&id=20-79-2"></script>