For-loop性能:将数组长度存储在variables中

考虑相同循环迭代的两个版本:

for (var i = 0; i < nodes.length; i++) { ... } 

 var len = nodes.length; for (var i = 0; i < len; i++) { ... } 

后者的版本是否比前者更快?

更新date:16/12/2015

由于这个答案似乎仍然得到很多意见,我想重新审视浏览器和JS引擎不断发展的问题。

而不是使用JSPerf我已经放在一起使用原始问题中提到的两种方法循环通过数组的一些代码 。 我已经把代码放入函数中来分解function, 希望在真实世界的应用程序中完成:

 function getTestArray(numEntries) { var testArray = []; for(var i = 0; i < numEntries; i++) { testArray.push(Math.random()); } return testArray; } function testInVariable(testArray) { for (var i = 0; i < testArray.length; i++) { doSomethingAwesome(testArray[i]); } } function testInLoop(testArray) { var len = testArray.length; for (var i = 0; i < len; i++) { doSomethingAwesome(testArray[i]); } } function doSomethingAwesome(i) { return i + 2; } function runAndAverageTest(testToRun, testArray, numTimesToRun) { var totalTime = 0; for(var i = 0; i < numTimesToRun; i++) { var start = new Date(); testToRun(testArray); var end = new Date(); totalTime += (end - start); } return totalTime / numTimesToRun; } function runTests() { var smallTestArray = getTestArray(10000); var largeTestArray = getTestArray(10000000); var smallTestInLoop = runAndAverageTest(testInLoop, smallTestArray, 5); var largeTestInLoop = runAndAverageTest(testInLoop, largeTestArray, 5); var smallTestVariable = runAndAverageTest(testInVariable, smallTestArray, 5); var largeTestVariable = runAndAverageTest(testInVariable, largeTestArray, 5); console.log("Length in for statement (small array): " + smallTestInLoop + "ms"); console.log("Length in for statement (large array): " + largeTestInLoop + "ms"); console.log("Length in variable (small array): " + smallTestVariable + "ms"); console.log("Length in variable (large array): " + largeTestVariable + "ms"); } runTests(); runTests(); runTests(); 

为了尽可能公正地进行testing,每次testing运行5次,结果取平均值。 我也运行了整个testing,包括3次数组的生成。 在我的机器上的Chrome上进行testing表明,使用每种方法的时间几乎相同。

记住这个例子有点玩笑,事实上大部分的例子都是从应用程序的上下文中提取出来的,可能会产生不可靠的信息,因为你的代码正在做的其他事情可能会直接或间接地影响性能。

底线

确定什么最适合您的应用程序的最好方法是自己testing一下! JS引擎,浏览器技术和CPU技术不断发展,所以您必须始终在自己的应用程序环境中testing自己的性能。 还有一点值得问问自己,是否有性能问题,如果你没有花费时间进行微观优化,那么用户感觉不到的问题可以更好地解决错误和添加function,从而使用户更快乐:)。

原始答案:

后者会稍微快一点。 length属性不会迭代数组来检查元素的数量,但是每次在数组上调用该数组时,都必须解除引用。 通过将长度存储在variables中,循环的每次迭代都不需要数组解引用。

如果你对在javascript中使用不同的数组循环方式感兴趣,那么看看这个jsperf

接受的答案是不正确的,因为任何体面的引擎应该能够通过如此简单的循环体提升属性载入循环。

看到这个jsperf – 至less在V8中,有趣的是看看实际存储在variables中是如何改变寄存器分配的 – 在使用variables的代码中, sumvariables存储在栈中,而array.length -in-a它的回路代码存储在一个寄存器中。 我假设SpiderMonkey和Opera也有类似的情况发生。

据笔者所说 , JSPerf使用不当 ,70%的时间。 这些所有答案中给出的这些破译的结果给人误解,人们从中得出错误的结论。

一些红旗将代码放入testing用例而不是函数中,而不是testing结果的正确性,或者使用一些消除死代码的方法,在设置或testing用例中定义函数而不是全局。为了保持一致性,在任何基准testing之前,都要先testing一下testingfunction,这样编译就不会在定时部分发生。

如果nodesDOM nodeList nodes那么第二个循环会快得多,因为在第一个循环中,每次迭代时都要查找DOM(代价非常高)。 jsperf

我相信nodes.length已经被定义,并且在每次使用时都不会被重新计算。 所以第一个例子会更快,因为它定义了一个更less的variables。 虽然区别将是不可知的。

根据w3schools“减less活动在循环”以下被认为是不好的代码:

 for (i = 0; i < arr.length; i++) { 

以下是被认为是好的代码:

 var arrLength = arr.length; for (i = 0; i < arrLength; i++) { 

由于访问DOM的速度很慢,下面是为了testing这个理论而写的:

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>my test scripts</title> </head> <body> <button onclick="initArray()">Init Large Array</button> <button onclick="iterateArraySlowly()">Iterate Large Array Slowly</button> <button onclick="iterateArrayQuickly()">Iterate Large Array Quickly</button> <p id="slow">Slow Time: </p> <p id="fast">Fast Time: </p> <p id="access"></p> <script> var myArray = []; function initArray(){ var length = 1e6; var i; for(i = 0; i < length; i++) { myArray[i] = i; } console.log("array size: " + myArray.length); } function iterateArraySlowly() { var t0 = new Date().getTime(); var slowText = "Slow Time: " var i, t; var elm = document.getElementById("slow"); for (i = 0; i < myArray.length; i++) { document.getElementById("access").innerHTML = "Value: " + i; } t = new Date().getTime() - t0; elm.innerHTML = slowText + t + "ms"; } function iterateArrayQuickly() { var t0 = new Date().getTime(); var fastText = "Fast Time: " var i, t; var elm = document.getElementById("fast"); var length = myArray.length; for (i = 0; i < length; i++) { document.getElementById("access").innerHTML = "Value: " + i; } t = new Date().getTime() - t0; elm.innerHTML = fastText + t + "ms"; } </script> </body> </html>