【问题标题】:Is it safe to reuse the array passed to .apply()?重用传递给 .apply() 的数组是否安全?
【发布时间】:2015-11-03 12:32:04
【问题描述】:

我需要围绕其他函数创建包装函数。众所周知,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

它在我检查过的所有浏览器中都可以正常工作,但我希望在这里能够适应未来。

【问题讨论】:

  • 很大程度上取决于这些// do some wrappy things here 是什么。你能告诉我们你在那里做什么吗?
  • 你为什么要使用数组而不是fun.apply(this, arguments)
  • @Bergi 1)我不做任何与参数相关的事情,但我认为这不重要 2)因为将“参数”作为参数传递给任何函数(甚至 .apply( )) 禁用 V8 中的优化(我认为其他地方也是如此)
  • 这个 IEFE 完全没有必要顺便说一句,你已经有了一个函数作用域。
  • 1) 好吧,如果它确实调用了一些用户提供的函数, 可能会对您的 static-args 方法造成一些危害。 2) 不,将arguments 传递给apply 在V8 中非常好

标签: javascript arguments parameter-passing


【解决方案1】:

传递给.apply() 的数组是否被复制到其他地方,是否由当前的 EcmaScript 规范保证?

是的。 apply method 确实使用CreateListFromArrayLike 将数组(或您传入的任何内容)转换为单独的参数列表,然后将其传递并从中创建用于调用的arguments 对象以及设置参数.

【讨论】:

    【解决方案2】:

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

    令 argList 为 CreateListFromArrayLike(argArray)。

    返回调用(func, thisArg, argList)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 2012-02-11
      相关资源
      最近更新 更多