javascript函数和参数对象,是否涉及成本

javascript函数和参数对象,是否涉及成本,javascript,performance,Javascript,Performance,在web和框架中经常可以看到这样的代码: var args = Array.prototype.slice.call(arguments); 在这样做的过程中,您可以将参数对象转换为一个真实的数组(就像JS有真实的数组一样),并且它允许应用数组原型中的任何数组方法,等等 我记得在某个地方读到过这样一篇文章:直接访问参数对象可能比数组克隆或命名参数的明显选择要慢得多。这是真的吗?在什么情况下/浏览器会因此受到性能惩罚?你知道有关于这个主题的文章吗 更新有趣的发现使我之前读到的内容无效。。。希望这

在web和框架中经常可以看到这样的代码:

var args = Array.prototype.slice.call(arguments);
在这样做的过程中,您可以将参数
对象
转换为一个真实的
数组
(就像JS有真实的数组一样),并且它允许应用数组原型中的任何数组方法,等等

我记得在某个地方读到过这样一篇文章:直接访问
参数
对象可能比数组克隆或命名参数的明显选择要慢得多。这是真的吗?在什么情况下/浏览器会因此受到性能惩罚?你知道有关于这个主题的文章吗

更新有趣的发现使我之前读到的内容无效。。。希望这个问题能从写这篇文章的人那里得到更多的答案

在那一部分的底部写着:

性能神话和真相

始终创建arguments对象 只有两个例外是 将其声明为名称的情况 在一个函数或它的一个函数内部 形式参数。没关系 无论是否使用

这与下列条款相冲突:

然而,使用它不是一个好主意 理由如下:

  • 演出
  • 保安
arguments对象不是在每次调用函数时自动创建的,JavaScript引擎只会在需要时创建它(如果使用的话)。就性能而言,这种创造不是免费的。根据浏览器的不同,使用参数与不使用参数之间的差异可能会慢1.5倍到4倍

很明显,不能两者都正确,那么哪一个是正确的呢

ECMA顽固派Dmitrty Soshnikov说:

“JavaScript引擎”到底是什么 意味?你从哪儿弄来的 信息?尽管在某些情况下,这可能是真的 实施(是的,这是好的 优化作为所有需要的信息 上下文在解析时可用 代码,因此无需创建 参数对象,如果找不到它 但正如您所知 ECMA-262-3语句,即 对象每次在 输入执行上下文


参数有两个问题:一个是它不是一个真正的数组。第二个是它只能包含所有参数,包括显式声明的参数。例如:

function f(x, y) {
    // arguments also include x and y
}
这可能是最常见的问题,您想要其余的参数,而不需要
x
y
中已有的参数,因此您想要这样的参数:

var rest = arguments.slice(2);
但是不能,因为它没有
slice
方法,所以必须手动应用
Array.prototype.slice

我必须说,我没有看到仅仅为了性能而将所有参数转换为实际数组,只是为了方便调用数组方法。我必须做一些分析才能知道什么是真正更快的,也可能取决于什么更快,但我的猜测是,如果您不想调用数组方法,那么没有太大的区别,在这种情况下,您别无选择,只能将其转换为实实在在的数组,或者使用call或apply手动应用这些方法

好消息是,在ECMAScript(Harmony?)的新版本中,我们可以编写以下内容:

function f(x, y, ...rest) {
   // ...
}

我们将能够忘记所有那些难看的解决办法。

一些q&d测试。使用预定义的
参数似乎是最快的,但这样做并不总是可行的。如果函数的算术性事先未知(因此,如果函数可以或必须接收可变数量的参数),我认为调用一次
Array.prototype.slice
将是最有效的方法,因为在这种情况下,使用
参数
对象的代价是最低的。

我反对接受的答案。
我编辑了测试,请参见此处:
我添加了对
slice
方法的测试和对预分配数组的内存复制的测试。后者在我的电脑中效率要高出数倍。
正如您所看到的,性能测试页面中的前两个内存复制方法速度较慢,这不是因为循环,而是因为
push
调用。
总之,
切片
似乎是处理
参数
的最差方法(不包括
推送
方法,因为它们的代码长度甚至不比更有效的预分配方法短得多)。
另外,
apply
函数的性能相当好,并且本身不会对性能造成太大影响,这可能会引起人们的兴趣

第一个现有测试:

function f1(){
    for(var i = 0, l = arguments.length; i < l; i++){
        res.push(arguments[i])
    }
}
函数f1(){
for(var i=0,l=arguments.length;i
新增测试:

function f3(){
    var len = arguments.length;
    res = new Array(len);
    for (var i = 0; i < len; i++)
         res[i] = arguments[i];
}

function f4(){
    res = Array.prototype.slice.call(arguments);
}

function f5_helper(){
    res = arguments;
}
function f5(){
    f5_helper.apply(null, arguments);
}

function f6_helper(a, b, c, d){
    res = [a, b, c, d];
}
function f6(){
    f6_helper.apply(null, arguments);
}
函数f3(){
var len=arguments.length;
res=新阵列(len);
对于(变量i=0;i
有一段时间没有人对此进行测试,所有链接都已失效。以下是一些新的结果:

function loop(){
  var res = []
  for(var i = 0, l = arguments.length; i < l; i++){
    res.push(arguments[i])
  }
}

function loop_variable(){
  var res = []
  var args = arguments
  for(var i = 0, l = args.length; i < l; i++){
    res.push(args[i])
  }
  return res
}

function slice(){
    return Array.prototype.slice.call(arguments);
}

function spread(){
    return [...arguments];
}

function do_return(){
    return arguments;
}

function literal_spread(){
    return [arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9]];
}
函数循环(){
var res=[]
for(var i=0,l=arguments.length;i