这话我听过好几次了。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是一种解释型语言,而不是编译型语言。每条指令都翻译成一种以上的机器语言,你不应该关心那些血腥的细节。
那些谈论使用——(或++)来有效使用汇编指令的人是错误的。这些指令适用于整数算术,在JavaScript中没有整数,只有数字。
您应该编写可读的代码。
其他回答
i——或i++占用的时间并不多。如果你深入到CPU架构中,++比——更快,因为——操作会做2的补位,但它发生在硬件内部,所以这将使它更快,而且++和——之间没有太大的区别,而且这些操作被认为是CPU消耗的时间最少的。
for循环是这样运行的:
在开始时初始化变量一次。 检查循环的第二个操作数中的约束,<,>,<=等。 然后应用循环。 递增循环,循环再次抛出这些进程。
所以,
for (var i = Things.length - 1; i >= 0; i--) {
Things[i]
};
将计算数组的长度只有一次在开始时,这不是很多时间,但是
for(var i = array.length; i--; )
将计算每个循环的长度,因此它将消耗大量时间。
我试图用这个答案给出一个广泛的图景。
以下括号中的想法是我的想法,直到我最近测试了这个问题:
对于像C/ c++这样的低级语言,代码被编译后,当一个变量为零(或非零)时,处理器有一个特殊的条件跳转命令。 同样,如果你关心这么多优化,你可以使用++i而不是i++,因为++i是一个单处理器命令,而i++意味着j=i+1, i=j。
真正快速的循环可以通过展开它们来完成:
for(i=800000;i>0;--i)
do_it(i);
它可以比
for(i=800000;i>0;i-=8)
{
do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}
但原因可能相当复杂(游戏邦注:游戏中存在处理器命令预处理和缓存处理的问题)。
就高级语言而言,比如JavaScript,如果你依赖于循环的库和内置函数,你就可以优化。让他们决定怎么做最好。
因此,在JavaScript中,我建议使用类似
array.forEach(function(i) {
do_it(i);
});
它也不太容易出错,浏览器也有机会优化您的代码。
[注:不仅是浏览器,而且你也有一个空间来轻松优化,只需重新定义forEach函数(依赖于浏览器),以便它使用最新的最佳技巧!]: @A.M.K。表示在特殊情况下更值得使用数组。Pop或array.shift。如果你这么做了,把它放在窗帘后面。最大的过量是为forEach添加选项来选择循环算法。
此外,对于低级语言,如果可能的话,最好使用一些智能库函数来处理复杂的循环操作。
这些库也可以把东西(多线程)放在你背后,也可以让专门的程序员保持它们的更新。
我仔细研究了一下,发现在C/ c++中, 即使对于5e9 = (50,000x100,000)操作,如果测试是针对@alestanis所说的常量进行的,那么上升和下降之间也没有区别。(JsPerf的结果有时不一致,但总的来说都是一样的:你不能有很大的不同。) 所以——i恰好是一个相当“时髦”的东西。这只会让你看起来像一个更好的程序员。:)
另一方面,在5e9的情况下,当我走10秒时,展开时间从12秒缩短到2.5秒,当我走20秒时,展开时间缩短到2.1秒。它没有优化,而优化使事情缩短到不可估量的时间。:)(展开可以用我上面的方法完成,也可以用i++完成,但这并没有在JavaScript中带来进步。)
总而言之:保持i——/i++和++i/i++的区别来面试,坚持数组。forEach或其他复杂的库函数。;)
好吧,我不了解JavaScript,它应该只是一个重新计算数组长度的问题,也许与关联数组有关(如果你只是递减,不太可能需要分配新条目——如果数组是密集的,也就是说。有人可能会为此进行优化)。
在低级汇编中,有一个循环指令,称为DJNZ(如果非零则递减和跳跃)。因此,递减和跳转都在一条指令中,使得它可能比INC和JL / JB略快(递增,如果小于则跳转/如果低于则跳转)。同样,与零比较比与其他数字比较简单。但所有这些都是边缘的,也取决于目标架构(可能会产生不同,例如智能手机上的Arm)。
我没想到这种低级别的差异会对解释语言产生这么大的影响,我只是在回答中没有看到DJNZ,所以我想分享一个有趣的想法。
这个人比较了javascript和很多浏览器中的循环。他还提供了一个测试套件,您可以自己运行这些测试。
在所有情况下(除非我在阅读中遗漏了一个),最快的循环是:
var i = arr.length; //or 10
while(i--)
{
//...
}
我在jsbench上做了一个比较。
正如alestani指出的那样,在升序循环中需要花费时间的一件事是,对于每次迭代,计算数组的大小。在这个循环中:
for ( var i = 1; i <= array.length; i++ )
每次增加i,你就计算。length。
for ( var i = 1, l = array.length; i <= l; i++ )
当你声明i时,你只对.length求值一次。
for ( var i = array.length; i--; )
比较是隐式的,它发生在i递减之前,并且代码非常可读。然而,你在循环中放入的东西会产生很大的不同。
循环调用函数(在其他地方定义):
for (i = values.length; i-- ;) {
add( values[i] );
}
内联代码循环:
var sum = 0;
for ( i = values.length; i-- ;) {
sum += values[i];
}
如果你可以内联你的代码,而不是调用一个函数,而不牺牲易读性,你可以有一个数量级的速度循环!
注意:由于浏览器越来越擅长内联简单的函数,这实际上取决于你的代码有多复杂。所以,先配置再优化,因为
瓶颈可能在其他地方(ajax, reflow,…) 你可以选择一个更好的算法 您可以选择更好的数据结构
但是请记住:
代码是为了让人阅读而写的,只是顺便让机器执行。