为什么arr = []比arr = new Array更快?

时间:2011-09-10 22:33:52

标签: javascript performance

我运行此代码并获得以下结果。我很想知道为什么[]更快?

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
  • 使用[]:299ms
  • 使用new:363毫秒

感谢Raynos这里有benchmark此代码以及更多可能的方法来定义变量。

enter image description here

5 个答案:

答案 0 :(得分:190)

进一步扩大之前的答案......

从一般编译器的角度出发,忽略特定于VM的优化:

首先,我们将进行词法分析阶段,我们会对代码进行标记。

举例来说,可以生成以下令牌:

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

希望这应该为您提供足够的可视化,以便您了解需要多少(或更少)处理。

  1. 基于上述标记,我们知道ARRAY_INIT将始终生成一个数组。因此,我们只需创建一个数组并填充它。至于歧义,词法分析阶段已经将ARRAY_INIT与对象属性访问器(例如obj[foo])或字符串/正则表达式文字中的括号区分开(例如“foo [] bar”或/ [] /)

  2. 这是微不足道的,但我们还有更多new Array的令牌。此外,还不完全清楚我们只是想创建一个数组。我们看到“新”令牌,但“新”令牌是什么?然后我们看到IDENTIFIER标记,表示我们想要一个新的“数组”,但JavaScript VM通常不区分IDENTIFIER标记和“本机全局对象”的标记。因此...

  3. 每次遇到IDENTIFIER令牌时,我们都必须查找范围链。 Javascript VM包含每个执行上下文的“激活对象”,其中可能包含“arguments”对象,本地定义的变量等。如果我们无法在Activation对象中找到它,我们将开始查找范围链,直到我们到达全局范围。如果找不到任何内容,我们会抛出ReferenceError

  4. 一旦我们找到变量声明,我们就会调用构造函数。 new Array是一个隐式函数调用,经验法则是函数调用在执行期间较慢(因此静态C / C ++编译器允许“函数内联” - SpiderMonkey等JS JIT引擎必须执行以下操作 - 即时)

  5. Array构造函数已重载。 Array构造函数实现为本机代码,因此它提供了一些性能增强,但仍需要检查参数长度并相应地执行操作。此外,如果只提供了一个参数,我们需要进一步检查参数的类型。 new Array(“foo”)产生[“foo”],其中新的Array(1)产生[undefined]

  6. 所以为了简化它:使用数组文字,VM知道我们想要一个数组;使用new Array,VM需要使用额外的CPU周期来确定实际的new Array

答案 1 :(得分:27)

一个可能的原因是new Array需要在Array上进行名称查找(您可以在范围内使用该名称的变量),而[]则不需要。

答案 2 :(得分:2)

好问题。 第一个示例称为数组文字。它是在许多开发人员之间创建数组的首选方式。可能是性能差异是由检查新的Array()调用的参数然后创建对象引起的,而文字直接创建了一个数组。

我认为相对较小的性能差异支持了这一点。顺便说一句,您可以使用Object和object literal {}进行相同的测试。

答案 3 :(得分:1)

这有点道理

  

对象文字使我们能够编写支持大量的代码   功能仍然使它相对简单   我们代码的实施者。无需直接调用构造函数或   维护传递给函数等的参数的正确顺序

http://www.dyn-web.com/tutorials/obj_lit.php

答案 4 :(得分:1)

另外,有趣的是,如果预先知道数组的长度 (元素将在创建后立即添加),则可以使用 array构造函数在最近的Google Chrome 70+中, length 的速度更快

  • 新阵列( %ARR_LENGTH% ” – 100%(更快)

  • [] ” – 160-170%(较慢)

Chart with results of the measures.

可以在这里找到测试-https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2

注意:此结果在 Google Chrome v.70 + 上进行了测试;在 Firefox v.70 和IE中,这两个版本几乎相等。