重用传递给 .apply() 的数组是否安全?

Is it safe to reuse the array passed to .apply()?

我需要围绕其他函数创建包装函数。众所周知,arguments 对象非常古怪,不能逐字传递给任何函数。 V8 中的数组创建也不便宜。所以我能想出的最快代码是这样的:

function wrap (fun) {      
  // reuse the same array object for each call
  var args = [];
  var prevLen = 0;
  
  return function () {
    
    // do some wrappy things here
    
    // only set args.length if it changed (unlikely)
    var l = arguments.length;
    if (l != prevLen) {
      prevLen = args.length = l;
    }
    
    // copy the args and run the functon
    for (var i = 0; i < l; i++) {
      args[i] = arguments[i];
    }
    fun.apply(this, args);
    
  };
  
}

var test = wrap(function (rec) {
  document.write(arguments[1] + '<br />');
  if (rec) test(false, 'something else');
  document.write(arguments[1] + '<br />');
});
test(true, 'something');

这样我就可以避免创建或更改数组对象的长度,除非确实需要。性能提升相当严重。

问题:我到处都使用同一个数组,它可能会在函数调用完成之前发生变化(参见示例)

问题: 传递给 .apply() 的数组是否复制到 all JavaScript 实现中的其他地方?当前的 EcmaScript 规范是否保证第四行输出永远不会是 something else?

它在我检查过的所有浏览器中都运行良好,但我想在这里面向未来。

根据 the spec 它确实应该被复制所以代码似乎是安全的。

Let argList be CreateListFromArrayLike(argArray).

Return Call(func, thisArg, argList).

Is the array passed to .apply() copied to somewhere else, and is it guaranteed by the current EcmaScript spec?

是的。然后传递 apply method does convert the array (or whatever you pass in) to a separate arguments list using CreateListFromArrayLike,并从中创建用于调用的 arguments 对象并设置参数。