为什么在Javascript中push方法比通过数组索引放置值慢得多

为什么在Javascript中push方法比通过数组索引放置值慢得多,javascript,arrays,performance,hashtable,benchmarking,Javascript,Arrays,Performance,Hashtable,Benchmarking,我很不明白为什么这个测试: 表明 a.push(Math.random()); 速度比我们慢十倍多 a[i] = Math.random(); 你能解释一下为什么会这样吗?是什么神奇的“推”使它如此缓慢?(与其他有效的方法相比,速度太慢了) 编辑 注:推压测试有偏差。我每次迭代都会增加数组的大小!仔细阅读接受的答案 你能解释一下为什么会这样吗 因为你的测试有缺陷。push总是附加到现有的a数组中,使其更大,而第二个测试只使用前1000个索引。 在这里使用设置是不够的,您必须在每个fo

我很不明白为什么这个测试:

表明

 a.push(Math.random());
速度比我们慢十倍多

 a[i] = Math.random();
你能解释一下为什么会这样吗?是什么神奇的“推”使它如此缓慢?(与其他有效的方法相比,速度太慢了)

编辑

注:推压测试有偏差。我每次迭代都会增加数组的大小!仔细阅读接受的答案

你能解释一下为什么会这样吗

因为你的测试有缺陷。
push
总是附加到现有的
a
数组中,使其更大,而第二个测试只使用前1000个索引。 在这里使用
设置
是不够的,您必须在每个for循环之前重置
a
数组:

除此之外,对
push
的方法调用可能会有一些开销,与使用for循环的索引相比,确定当前数组长度可能需要额外的时间

通常情况下是这样的——方法就是为了完成这个操作,并且使一些代码更容易阅读。虽然有一些人认为一个版本比另一个版本快,但两个版本在浏览器中的优化程度相同。结果变化如此之大,以至于它实际上是无关紧要的使用更好理解的方法。

因为.push()是函数调用,而另一个是直接赋值。直接分配总是更快

请记住,在javascript中,数组与其他对象一样都是对象。这意味着您可以直接将属性指定给它们

在数组的特殊情况下,它们有一个内置的length属性,可以在幕后进行更新(还有很多其他的优化,但现在这并不重要)

在常规对象中,可以执行此操作,但它不是数组:

var x = {
   0: 'a',
   1: 'b',
   2: 'c'
};
但是,由于数组和散列都是对象,所以这是等效的

   var x = [
      'a',
      'b',
      'c'
   ];

由于在第二种情况下x是一个数组,因此长度会自动计算并可用。

这只是因为谷歌决定在优化数组索引方面投入更多的工作,而不是在Chrome中优化推送方法

如果现在有更多的人尝试了它,那么看看测试结果,就会发现不同浏览器之间,甚至同一浏览器的不同版本之间的性能差异很大


现在浏览器编译Javascript代码,这意味着浏览器将代码转换为运行解释的Javascript要快得多的东西。编译器对代码的处理方式决定了不同的处理方式的执行方式。不同的编译器可以更好地优化某些东西,从而获得不同的性能。

什么更快:赋值还是函数调用,查找数组的长度并执行赋值?在Firefox上,两者之间的差异要小得多。@Fabriciomatté你建议“查找长度”吗太贵了@bluesm没有,但这是常规作业没有的开销。另外,
.push()
接受N个参数以推送到数组的末尾。尝试为数组.prototype.push编写一个polyfill,就像它不存在一样,你会发现它比简单的赋值要复杂得多
=]
另请参见哪个问题提出了完全相反的问题,使其更大,然后分配非常昂贵的内存?@bluesm:是的,内存分配是杀死
推送
版本的原因。@FabricioMatté:是的,每个测试循环。它运行一次,然后测试(1000次循环)运行多次,并测量其执行时间。重复此过程以获得平均运行时间。@FabricioMatté:看。你明白我的意思吗?在进行大量单次测试之前,安装只完成一次。@Bergi是的,我明白你的意思。但我是弱智。我在错误的测试中添加了console.log,删除了一些注释以减少混乱。这里有一个适当的测试来证明你的观点:它们不是等价的。在第一种情况下,键被转换为字符串。每当你访问一个对象(不是数组)上的属性时,它就会被转换成一个字符串。对于一些相等的定义来说,它们是等价的。这意味着它已经在chrome 72中修复了。资料来源:Bergi