Javascript 为什么 arr = [] 比 arr = new Array 快?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7375120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is arr = [] faster than arr = new Array?
提问by Mohsen
I ran this code and got the below result. I curious to know why []
is faster?
我运行了这段代码并得到了以下结果。我很想知道为什么[]
更快?
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')
- using
[]
: 299ms - using
new
: 363ms
- 使用
[]
:299ms - 使用
new
:363ms
Thanks to Raynoshere is a benchmarkof this code and some more possible way to define a variable.
感谢Raynos,这里是这段代码的基准测试和一些更可能的定义变量的方法。
回答by Roger Poon
Further expanding on previous answers...
进一步扩展以前的答案......
From a general compilers perspective and disregarding VM-specific optimizations:
从一般编译器的角度来看,不考虑特定于 VM 的优化:
First, we go through the lexical analysis phase where we tokenize the code.
首先,我们经历词法分析阶段,在此阶段对代码进行标记。
By way of example, the following tokens may be produced:
例如,可以产生以下令牌:
[]: 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)
Hopefully this should provide you a sufficient visualization so you can understand how much more (or less) processing is required.
希望这应该为您提供足够的可视化,以便您了解需要更多(或更少)的处理。
Based on the above tokens, we know as a fact ARRAY_INIT will always produce an array. We therefore simply create an array and populate it. As far as ambiguity, the lexical analysis stage has already distinguished ARRAY_INIT from an object property accessor (e.g.
obj[foo]
) or brackets inside strings/regex literals (e.g. "foo[]bar" or /[]/)This is miniscule, but we also have more tokens with
new Array
. Furthermore, it's not entirely clear yet that we simply want to create an array. We see the "new" token, but "new" what? We then see the IDENTIFIER token which signifies we want a new "Array," but JavaScript VM's generally do not distinguish an IDENTIFIER token and tokens for "native global objects." Therefore...We have to look up the scope chain each time we encounter an IDENTIFIER token. Javascript VMs contain an "Activation object" for each execution context which may contain the "arguments" object, locally defined variables, etc. If we cannot find it in the Activation object, we begin looking up the scope chain until we reach the global scope. If nothing is found, we throw a
ReferenceError
.Once we've located the variable declaration, we invoke the constructor.
new Array
is an implicit function call, and the rule of thumb is that function calls are slower during execution (hence why static C/C++ compilers allow "function inlining" - which JS JIT engines such as SpiderMonkey have to do on-the-fly)The
Array
constructor is overloaded. The Array constructor is implemented as native code so it provides some performance enhancements, but it still needs to check for arguments length and act accordingly. Moreover, in the event only one argument is supplied, we need to further check the type of the argument. new Array("foo") produces ["foo"] where as new Array(1) produces [undefined]
基于上述标记,我们知道 ARRAY_INIT 将始终生成一个数组。因此,我们只需创建一个数组并填充它。就歧义而言,词法分析阶段已经将 ARRAY_INIT 与对象属性访问器(例如
obj[foo]
)或字符串/正则表达式中的括号(例如“foo[]bar”或 /[]/)区分开来这是微不足道的,但我们还有更多带有
new Array
. 此外,目前还不完全清楚我们只是想创建一个数组。我们看到了“new”令牌,但是“new”是什么?然后我们会看到 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]
So to simplify it all: with array literals, the VM knows we want an array; with new Array
, the VM needs to use extra CPU cycles to figure out what new Array
actuallydoes.
所以为了简化这一切:使用数组字面量,VM 知道我们需要一个数组;使用new Array
,VM 需要使用额外的 CPU 周期来确定new Array
实际执行的操作。
回答by hammar
One possible reason is that new Array
requires a name lookup on Array
(you can have a variable with that name in scope), whereas []
does not.
一个可能的原因是new Array
需要名称查找Array
(您可以在范围内使用具有该名称的变量),[]
而不需要。
回答by Laurent Zuijdwijk
Good question. The first example is called an array literal. It is the prefered way to create arrays among many developers. It could be that the performance difference is caused by checking the arguments of the new Array() call and then creating the object, while the literal creates an array directly.
好问题。第一个示例称为数组字面量。它是许多开发人员创建数组的首选方式。性能差异可能是由于检查 new Array() 调用的参数然后创建对象造成的,而文字直接创建数组。
The relatively small difference in performance supports this point I think. You could do the same test with the Object and object literal {} by the way.
我认为性能上相对较小的差异支持了这一点。顺便说一下,您可以对 Object 和对象文字 {} 进行相同的测试。
回答by lnguyen55
This would make some sense
这会有些道理
Objects literals enable us to write code that supports lots of features yet still make it a relatively straightforward for the implementers of our code. No need to invoke constructors directly or maintain the correct order of arguments passed to functions, etc.
对象字面量使我们能够编写支持许多功能的代码,但仍然使我们的代码实现者相对简单。无需直接调用构造函数或维护传递给函数的参数的正确顺序等。
回答by Oleg Zarevennyi
Also, interesting, if the length of the array is known in advance(elements will be added just after creation), the use of an array constructorwith a specified lengthis much fasteron recent Google Chrome 70+.
此外,有趣的是,如果预先知道数组的长度(元素将在创建后立即添加),则在最近的 Google Chrome 70+ 上使用具有指定长度的数组构造函数要快得多。
"new Array(%ARR_LENGTH%)" – 100% (faster)!
"[]" – 160-170% (slower)
“新数组(%ARR_LENGTH% )”——100% (更快)!
“ []” – 160-170% (较慢)
The test can be found here - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2
测试可以在这里找到 - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2
Note: this result tested on Google Chrome v.70+; in the Firefox v.70and IE both variants almost equal.
注意:此结果在Google Chrome v.70+上测试;在Firefox v.70和 IE 中,这两个变体几乎相等。