前端录网站,记录前端点点滴滴,帮助程序猿快速成长!

JavaScript的arguments及其子对象

js
首先一个最大的问题是,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及其子对象