JavaScript中的concat和push函数的性能比较

3

这里有一个关于jsperf的测试:

http://jsperf.com/javascript-array-concat-vs-push

它显示concat更快,但如果你在初始数组中得到了这个结果,而不使用第三个变量,那么concat会慢得多,非常慢:

for (i = 10000; i > 0; i--) {
   arr1 = arr1.concat(arr2);
}

即使您使用相同名称的本地变量,结果也是相同的:
for (i = 10000; i > 0; i--) {
   var arr1 = arr1.concat(arr2);
}

有人能解释一下这是什么意思吗?

1
不确定我是否理解问题,“concat”和“push”执行不同的操作,一个是将两个数组连接起来,另一个是向数组中添加元素,但是如果你使用“apply”的一些技巧,你可以用一行代码将一个数组中的所有值推送到另一个数组中,而不需要迭代,但是当然本地方法通常更快。 - adeneo
1
首先,您正在显着更改初始性能测试的条件:每次迭代附加的数组更大。此外,如果不使用第三个变量,则会在每次迭代中创建和销毁一个辅助变量,这可能解释了额外的性能下降。 - Etheryte
1
你的两个例子是等价的。Javascript 变量具有函数作用域,而不是块级作用域,因此变量声明被提升到循环外部。 - Barmar
在我看来,jsperf正在比较不相干的事物。concat测试将结果放入一个新变量中,因此它只是多次连接相同的两个数组。push测试修改了其中一个原始数组,因此它在每次测试迭代中都会不断增长。你的concat测试就像基准测试中的push测试,因为你正在将结果保存在arr1中。这就是为什么性能类似于push基准测试的原因。 - Barmar
@Barmar,问题就在这里,它们并不相似。如果你修改测试并将结果保存在arr1而不是arr3中,那么concat会慢99%。我猜Nit可能是对的,使用辅助变量,但我还没有被说服。 - ovi
显示剩余2条评论
1个回答

5

您在循环中改变了原始数组。

for (i = 10000; i > 0; i--) {
   arr1 = arr1.concat(arr2);
}

这里arr1数组的大小会不断增长,随着数组变得越来越大,性能会变慢因为它需要分配更多的内存。

for (i = 10000; i > 0; i--) {
   var arr3 = arr1.concat(arr2);
}

在这里,您正在分配给一个新变量而不改变arr1arr2,因此测试连接两个小数组的性能。

arr1的情况下,您正在测试将一个大数组与一个小数组连接起来的性能。


5
你误解了重点。这个问题是关于concat和push的区别。 - ovi
1
它可能比这更隐匿。因为arr3在其他任何地方都没有使用,优化器很有可能已经决定:“嘿,为什么还要连接?这个值毕竟被丢弃了,所以让我们假设我们已经这样做并提前终止”。 - Cogman
5
不,@ovi,这个问题的标题可能是“concat versus push”,但实际上的问题是“有人能解释一下这是什么意思吗?” - joeytwiddle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接