在web和框架中经常可以看到这样的代码:
var args = Array.prototype.slice.call(arguments);
在这样做的时候,你将参数Object
转换成一个实数组(就像JS有实数组一样),它允许你的Array
原型中的任何数组方法应用于它,等等。
我记得在某处读到过,直接访问arguments
对象可能比数组克隆或明显的命名参数选择慢得多。这是真的吗?在什么情况下/浏览器这样做会导致性能损失?你知道有什么关于这个主题的文章吗?
来自http://bonsaiden.github.com/JavaScript-Garden/#function.arguments的update有趣的发现使我之前读到的内容无效...希望这个问题能从写这篇文章的@Ivo Wetzel等人那里得到更多的答案。
在该部分的底部写着:
性能神话和事实
arguments对象总是被创建的,唯一的两个例外是它被声明为函数内部的一个名称或它的一个形参。它是否被使用并不重要。
这与http://www.jspatterns.com/arguments-considered-harmful/相冲突,后者声明:
但是,出于以下原因,使用参数并不是一个好主意:
arguments对象并不是在每次调用函数时自动创建的,如果使用了它,JavaScript引擎只会按需创建它。就性能而言,这种创造并不是免费的。根据浏览器的不同,使用参数和不使用参数之间的差异可能在1.5到4倍之间
显然,不可能两者都是正确的,那么哪一个是正确的呢?
ECMA死硬派Dmitrty Soshnikov说:
“JavaScript engine”到底指的是什么?你从哪里得到这个确切的信息的?尽管在某些实现中这可能是真的(是的,这是一个很好的优化,因为在解析代码时可以获得关于上下文的所有必要信息,所以如果在解析时找不到参数对象,则不需要创建参数对象),但是正如您知道的那样,每次进入执行上下文时,参数对象都会在中创建。
发布于 2011-03-16 22:10:43
Here's一些q&d测试。使用预定义的arguments
似乎是最快的,但这样做并不总是可行。如果事先不知道函数的数量(因此,如果函数可以或必须接收可变数量的参数),我认为调用一次Array.prototype.slice
将是最有效的方法,因为在这种情况下,使用arguments
对象的performance loss是最小的。
发布于 2011-03-16 21:11:56
arguments
有两个问题:一个是它不是真正的数组。第二个是它只能包含所有参数,包括显式声明的参数。举个例子:
function f(x, y) {
// arguments also include x and y
}
这可能是最常见的问题,您希望参数的rest,而不是x
和y
中已有的参数,所以您可能希望有这样的东西:
var rest = arguments.slice(2);
但是您不能这样做,因为它没有slice
方法,所以您必须手动应用Array.prototype.slice
。
我必须说,我还没有看到将所有参数转换为真正的数组仅仅是为了提高性能,只是为了方便调用array方法。我必须做一些分析才能知道哪些方法更快,这也可能取决于哪些方法更快,但我的猜测是,如果您不想调用Array方法,则没有太大区别,在这种情况下,您别无选择,只能将其转换为实际的数组,或者使用call或apply手动应用这些方法。
好消息是,在新版本的ECMAScript中(和谐?)我们将能够编写以下代码:
function f(x, y, ...rest) {
// ...
}
我们将能够忘记所有这些丑陋的变通方法。
发布于 2015-01-20 04:18:29
我反对这个公认的答案。
我编辑了测试,请看这里:http://jsperf.com/arguments-performance/6
我添加了slice
方法的测试和内存复制到预分配数组的测试。在我的电脑上,后者的效率要高出好几倍。
正如您所看到的,该性能测试页面中的前两个内存复制方法速度很慢,不是由于循环,而是由于push
调用。
总而言之,slice
似乎是使用arguments
最糟糕的方法(不包括push
方法,因为它们的代码甚至比更有效的预分配方法短不了多少)。
同样有趣的是,apply
函数运行得很好,本身没有太多的性能影响。
第一个现有的测试:
function f1(){
for(var i = 0, l = arguments.length; i < l; i++){
res.push(arguments[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);
}
https://stackoverflow.com/questions/5325554
复制相似问题