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

我运行了这段代码,得到了下面的结果。我很好奇为什么 []更快?

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:363ms

感谢 雷诺斯在这里是一个 基准的这段代码和一些更可能的方式来定义一个变量。

enter image description here

55308 次浏览

一个可能的原因是,new Array需要在 Array上进行名称查找(您可以在作用域中使用具有该名称的变量) ,而 []不需要。

这就说得通了

对象文本使我们能够编写支持大量 功能,但仍然使它成为一个相对简单的 不需要直接调用构造函数或 保持传递给函数等的参数的正确顺序。

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

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

我认为性能上相对较小的差异支持这一点。顺便说一下,您可以对 Object 和 Object 值{}进行相同的测试。

进一步扩展之前的答案..。

从一般编译器的角度来看,不考虑 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 令牌,它表示我们需要一个新的“ Array”,但 JavaScript VM 通常不区分 IDENTIFIER 令牌和“本机全局对象”令牌所以..。

  3. 每次遇到 IDENTIFIER 标记时,我们都必须查找范围链。Javascript VM 为每个执行上下文包含一个“激活对象”,这个对象可能包含“参数”对象、本地定义的变量等等。如果在 Activation 对象中找不到它,我们就开始查找范围链,直到到达全局范围。如果没有发现,我们抛出 ReferenceError

  4. 一旦我们找到了变量声明,我们就调用构造函数。new Array是一个隐函数调用,经验法则是函数调用在执行过程中会变慢(这就是为什么静态的 C/C + + 编译器允许“函数内联”——这就是像 SpiderMonkey 这样的 JS JIT 引擎必须动态执行的)

  5. Array构造函数被重载。Array 构造函数是作为本机代码实现的,因此它提供了一些性能增强,但是它仍然需要检查参数长度并相应地执行操作。此外,在只提供一个参数的情况下,我们需要进一步检查参数的类型。New Array (“ foo”)生成[“ foo”] ,而 new Array (1)生成[ unDefinition ]

因此,为了简化这一切: 对于数组文字,VM 知道我们需要一个数组; 对于 new Array,VM 需要使用额外的 CPU 周期来计算 new Array 事实上的功能。

另外,有趣的是,如果使用 提前知道数组的长度(元素将在创建后立即添加) ,那么在最近的 Google Chrome 70 + 中使用带有指定 长度数组构造函数数组构造函数就相当于使用 再快点

  • 新数组( % 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

注意: 这个结果在 谷歌浏览器诉70 + 上测试; 在 火狐 v.70和 IE 两个变体几乎相等。