为啥 arr = [] 比 arr = new Array 快?
Posted
技术标签:
【中文标题】为啥 arr = [] 比 arr = new Array 快?【英文标题】:Why is arr = [] faster than arr = new Array?为什么 arr = [] 比 arr = new Array 快? 【发布时间】:2011-11-14 13:32:00 【问题描述】:我运行了这段代码,得到了以下结果。我很想知道为什么[]
更快?
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
感谢Raynos,这是此代码的benchmark 以及定义变量的更多可能方式。
【问题讨论】:
你可能对jsperf感兴趣。 Benchmark 注意关键字new。这意味着“请降低效率”。它没有任何意义,并且需要浏览器进行正常的实例化而不是尝试进行优化。 @kinakuta 没有。他们都创建了新的不相等的对象。我的意思是[]
在源代码方面等同于new Array()
,而不是对象返回的形式表达式
是的,这不是很重要。但我想知道。
【参考方案1】:
进一步扩展之前的答案...
从一般编译器的角度来看,忽略特定于 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)
希望这应该为您提供足够的可视化,以便您了解需要更多(或更少)处理。
基于上述标记,我们知道 ARRAY_INIT 总是会产生一个数组。因此,我们只需创建一个数组并填充它。至于歧义,词法分析阶段已经将 ARRAY_INIT 与对象属性访问器(例如obj[foo]
)或字符串/正则表达式文字中的括号(例如“foo[]bar”或/[]/)区分开来
这是微不足道的,但我们还有更多带有new Array
的令牌。此外,尚不完全清楚我们只是想创建一个数组。我们看到了“新”令牌,但“新”是什么?然后我们会看到 IDENTIFIER 令牌,它表示我们想要一个新的“数组”,但 javascript VM 通常不区分 IDENTIFIER 令牌和“本地全局对象”的令牌。所以……
每次遇到 IDENTIFIER 令牌时,我们都必须查找作用域链。 Javascript VM 为每个执行上下文包含一个“激活对象”,其中可能包含“参数”对象、本地定义的变量等。如果我们在 Activation 对象中找不到它,我们开始查找作用域链,直到到达全局作用域.如果没有找到,我们会抛出一个ReferenceError
。
一旦我们找到了变量声明,我们就会调用构造函数。 new Array
是一个隐式函数调用,经验法则是函数调用在执行过程中速度较慢(因此静态 C/C++ 编译器允许“函数内联” - SpiderMonkey 等 JS JIT 引擎必须在 -飞)
Array
构造函数已重载。 Array 构造函数是作为本机代码实现的,因此它提供了一些性能增强,但它仍然需要检查参数长度并采取相应措施。此外,如果只提供一个参数,我们需要进一步检查参数的类型。 new Array("foo") 产生 ["foo"] 其中 new Array(1) 产生 [undefined]
所以为了简化这一切:使用数组字面量,VM 知道我们需要一个数组;使用 new Array
,VM 需要使用额外的 CPU 周期来确定 new Array
实际上做了什么。
【讨论】:
isn't a = new Array(1000);for(from 0 to 999)a[i]=i 比 a = [];for(from 0 to 999)a [i]=i 因为分配开销? 刚做了一个测试用例。如果您提前知道数组的大小,new Array(n) 会更快jsperf.com/square-braces-vs-new-array【参考方案2】:一个可能的原因是new Array
需要在Array
上进行名称查找(您可以在范围内拥有一个具有该名称的变量),而[]
不需要。
【讨论】:
检查参数也可能有帮助。Array
除了一个参数len
和多个参数。 []
只接受多个参数。 Firefox 测试也显示几乎没有区别。
我认为这是有道理的。在 IIFE 中运行 OP 的循环测试会对性能产生(相对) 实质性影响。包含var Array = window.Array
提高了new Array
测试的性能。
我认为这不对,因为这个 console.time('more vars new'); for(var i=0; i
【参考方案3】:
好问题。 第一个示例称为数组文字。它是许多开发人员创建数组的首选方式。可能是由于检查 new Array() 调用的参数然后创建对象导致性能差异,而字面量直接创建数组。
我认为相对较小的性能差异支持了这一点。顺便说一句,您可以对 Object 和 object literal 进行相同的测试。
【讨论】:
【参考方案4】:另外,有趣的是,如果事先知道数组的长度(元素将在创建后立即添加),则使用数组构造函数指定length 在最近的 Google Chrome 70+ 上更快。
"新数组( %ARR_LENGTH% )" – 100% (更快)!
"[]" – 160-170% (较慢)
测试可以在这里找到 - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2
注意:此结果在 Google Chrome v.70+ 上测试过;在 Firefox v.70 和 IE 中这两个变种几乎相等。
【讨论】:
【参考方案5】:这有点道理
对象字面量使我们能够编写支持大量 功能仍然使它相对简单 我们代码的实现者。无需直接调用构造函数或 保持传递给函数等的参数的正确顺序。
http://www.dyn-web.com/tutorials/obj_lit.php
【讨论】:
以上是关于为啥 arr = [] 比 arr = new Array 快?的主要内容,如果未能解决你的问题,请参考以下文章