这话我听过好几次了。JavaScript循环在向后计数时真的更快吗?如果有,为什么?我已经看到了一些测试套件示例,它们显示反向循环更快,但我找不到任何解释!
我假设这是因为循环不再需要在每次检查属性时评估它是否已经完成,它只检查最终的数值。
即。
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
这话我听过好几次了。JavaScript循环在向后计数时真的更快吗?如果有,为什么?我已经看到了一些测试套件示例,它们显示反向循环更快,但我找不到任何解释!
我假设这是因为循环不再需要在每次检查属性时评估它是否已经完成,它只检查最终的数值。
即。
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
当前回答
我不认为在JavaScript中说I比i++更快是有意义的。
首先,它完全依赖于JavaScript引擎实现。
其次,如果最简单的构造被JIT化并转换为本机指令,那么i++ vs i——将完全依赖于执行它的CPU。也就是说,在arm(移动电话)上,下降到0更快,因为递减和比较0是在一条指令中执行的。
也许,你认为一个比另一个更浪费,因为建议的方式是
for(var i = array.length; i--; )
但建议的方式不是因为一个比另一个快,而只是因为如果你写
for(var i = 0; i < array.length; i++)
然后是每个迭代数组。length必须被计算(更聪明的JavaScript引擎可能会发现循环不会改变数组的长度)。尽管它看起来像一个简单的语句,但它实际上是JavaScript引擎在底层调用的某个函数。
The other reason, why i-- could be considered "faster" is because JavaScript engine needs to allocate only one internal variable to control the loop (variable to the var i). If you compared to array.length or to some other variable then there had to be more than one internal variable to control the loop, and the number of internal variables are limited asset of a JavaScript engine. The less variables are used in a loop the more chance JIT has for optimization. That's why i-- could be considered faster...
其他回答
这个人比较了javascript和很多浏览器中的循环。他还提供了一个测试套件,您可以自己运行这些测试。
在所有情况下(除非我在阅读中遗漏了一个),最快的循环是:
var i = arr.length; //or 10
while(i--)
{
//...
}
简短的回答
对于普通代码,特别是在像JavaScript这样的高级语言中,i++和i——在性能上没有区别。
性能标准是在for循环和compare语句中的使用。
这适用于所有高级语言,并且基本上独立于JavaScript的使用。解释是最后一行的汇编代码。
详细解释
在循环中可能会出现性能差异。背景是,在汇编代码级别上,您可以看到compare with 0只是一个语句,不需要额外的寄存器。
这种比较是在循环的每一次传递中进行的,可能会导致可测量的性能改进。
for(var i = array.length; i--; )
将被求值为如下的伪代码:
i=array.length
:LOOP_START
decrement i
if [ i = 0 ] goto :LOOP_END
... BODY_CODE
:LOOP_END
注意,0是一个字面值,或者换句话说,是一个常量值。
for(var i = 0 ; i < array.length; i++ )
将被计算为如下的伪代码(假设是正常的解释器优化):
end=array.length
i=0
:LOOP_START
if [ i < end ] goto :LOOP_END
increment i
... BODY_CODE
:LOOP_END
注意,end是一个需要CPU寄存器的变量。这可能会在代码中调用额外的寄存器交换,并且需要在if语句中使用更昂贵的compare语句。
只是我的5美分
对于高级语言来说,可读性(有助于可维护性)作为一种较小的性能改进更为重要。
通常,从数组开始到结束的经典迭代更好。
从数组末端到开始的快速迭代会导致可能不需要的反向序列。
附言
正如在评论中问到的:-i和i-的区别在于i在递减之前或之后的求值。
最好的解释是尝试一下;-)下面是一个Bash示例。
% i=10; echo "$((--i)) --> $i"
9 --> 9
% i=10; echo "$((i--)) --> $i"
10 --> 9
好吧,我不了解JavaScript,它应该只是一个重新计算数组长度的问题,也许与关联数组有关(如果你只是递减,不太可能需要分配新条目——如果数组是密集的,也就是说。有人可能会为此进行优化)。
在低级汇编中,有一个循环指令,称为DJNZ(如果非零则递减和跳跃)。因此,递减和跳转都在一条指令中,使得它可能比INC和JL / JB略快(递增,如果小于则跳转/如果低于则跳转)。同样,与零比较比与其他数字比较简单。但所有这些都是边缘的,也取决于目标架构(可能会产生不同,例如智能手机上的Arm)。
我没想到这种低级别的差异会对解释语言产生这么大的影响,我只是在回答中没有看到DJNZ,所以我想分享一个有趣的想法。
回答这类问题的最好方法就是亲自去尝试。建立一个计算百万次迭代的循环,并以两种方式进行。对两个循环进行计时,并比较结果。
答案可能取决于您使用的浏览器。有些会有不同的结果。
它可以解释为JavaScript(以及所有语言)最终被转换为在CPU上运行的操作码。cpu总是只有一条指令用于与0进行比较,这非常快。
顺便说一句,如果你能保证count总是>= 0,你可以简化为:
for (var i = count; i--;)
{
// whatever
}