为什么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
感谢Raynos这里是这个代码的基准和一些更可能的方式来定义一个variables。
进一步扩大以前的答案…
从一般编译器的angular度来看,不考虑特定于虚拟机的优化:
首先,我们通过词法分析阶段来标记代码。
举例来说,可以生成以下令牌:
[]: 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)
希望这应该为您提供足够的可视化,以便您了解需要多less(或更less)处理。
-
基于上述标记,我们知道ARRAY_INIT将始终生成一个数组。 因此,我们只需创build一个数组并填充它。 就歧义而言,词法分析阶段已经将ARRAY_INIT与对象属性访问器(例如
obj[foo]
)或string/正则expression式文本中的括号(例如“foo [] bar”或/ [] /)区分开来 -
这是微不足道的,但我们也有更多的令牌与
new Array
。 而且,还不完全清楚,我们只是想创build一个数组。 我们看到“新”的标志,但“新”是什么? 然后,我们看到IDENTIFIER标记表示我们需要一个新的“Array”,但是JavaScript VM通常不会区分IDENTIFIER标记和“本地全局对象”的标记。 因此… -
每次遇到一个IDENTIFIER标记时,我们都要查找范围链。 Javascript虚拟机为每个执行上下文包含一个“激活对象”,可以包含“参数”对象,本地定义的variables等。如果我们在激活对象中找不到它,我们开始查找范围链,直到到达全局范围。 如果没有发现,我们抛出一个
ReferenceError
。 -
一旦findvariables声明,就调用构造函数。
new Array
是一个隐含的函数调用,经验法则是在执行过程中函数调用较慢(为什么静态C / C ++编译器允许“函数内联” – SpiderMonkey等JS JIT引擎必须在运行中) -
Array
构造函数被重载。 Array构造函数是作为本机代码实现的,所以它提供了一些性能增强,但是仍然需要检查参数长度并相应地采取行动。 而且,如果只提供一个参数,我们需要进一步检查参数的types。 new Array(“foo”)产生[“foo”],其中新的Array(1)产生[undefined]
所以为了简化这一切:使用数组文字,VM知道我们想要一个数组; 与new Array
,虚拟机需要使用额外的CPU周期来找出new Array
实际上做什么。
一个可能的原因是new Array
需要在Array
上进行名称查找(您可以在范围中使用该名称的variables),而[]
不需要。
好问题。 第一个例子被称为数组文字。 在许多开发人员中创build数组是最好的方式。 性能差异可能是由检查新的Array()调用的参数,然后创build对象引起的,而文字直接创build一个数组。
性能相对较小的差异支持这一点,我认为。 顺便说一下,你可以用Object和object literal来做相同的testing。
这会有一定的意义
对象文字使我们能够编写支持许多特性的代码,但对于我们的代码的实现者来说,它仍然是相对简单的。 不需要直接调用构造函数或维护传递给函数的参数的正确顺序等。