我从书上知道你应该像这样写 for 循环:
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
所以arr.length
不会每次都计算。
其他人说编译器会对此做一些优化,所以你可以这样写:
for(var i=0; i < arr.length; i++){
// blah blah
}
我只想知道实践中哪种方法最好?
我从书上知道你应该像这样写 for 循环:
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
所以arr.length
不会每次都计算。
其他人说编译器会对此做一些优化,所以你可以这样写:
for(var i=0; i < arr.length; i++){
// blah blah
}
我只想知道实践中哪种方法最好?
使用大多数现代浏览器执行此测试后:https : //jsben.ch/wY5fo
目前,最快的循环形式(在我看来也是最明显的句法)。
带有长度缓存的标准 for 循环
var i = 0, len = myArray.length;
while (i < len) {
// your code
i++
}
我想说,这绝对是我为 JavaScript 引擎开发人员鼓掌的一个案例。运行时应该为了清晰而不是聪明而优化。
截至 2016 年 6 月,在最新的 Chrome 中进行了一些测试(2016 年 5 月浏览器市场的 71%,并且还在增加):
我认为这个线程太旧了,它误导程序员认为他们需要缓存长度,或者使用带有递减的反向遍历 whiles 来获得更好的性能,编写比简单直接的 for 循环更易读且更容易出错的代码。因此,我建议:
如果您的应用程序迭代了很多项目,或者您的循环代码位于经常使用的函数中,那么简单的 for 循环就是答案:
for (var i = 0; i < arr.length; i++) {
// Do stuff with arr[i] or i
}
如果您的应用程序并没有真正迭代大量项目,或者您只需要在这里和那里进行小的迭代,那么使用标准的 forEach 回调或您选择的 JS 库中的任何类似函数可能更容易理解并且更不容易出错,因为index 变量作用域是关闭的,不需要使用方括号,直接访问数组值:
arr.forEach(function(value, index) {
// Do stuff with value or index
});
如果您确实需要在迭代数十亿行时花费几毫秒,并且数组的长度在整个过程中不会改变,则可以考虑在 for 循环中缓存长度。虽然我认为这在今天真的没有必要:
for (var i = 0, len = arr.length; i < len; i++) {
// Do stuff with arr[i]
}
现在是 2018 年,所以更新可能会很好......
我真的不得不不同意接受的答案。它在不同的浏览器上有所延迟。有的做forEach
快,有的for-loop
,有的while
在这里是所有方法的基准http://jsben.ch/mW36e
arr.forEach( a => {
// ...
}
并且因为您可以看到很多像这样的 for 循环,for(a = 0; ... )
所以值得一提的是,如果没有 'var' 变量将被全局定义,这会极大地影响速度,因此它会变慢。
Duff 的设备在 opera 上运行得更快,但在 Firefox 中则不然
var arr = arr = new Array(11111111).fill(255);
var benches =
[ [ "empty", () => {
for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
for(var a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
}]
, ["for-loop++", () => {
for(var a = 0, l = arr.length; a < l; a++)
var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
for(var a = 0; a < arr.length; ++a )
var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
for(var a = arr.length - 1; a >= 0; --a )
var b = arr[a] + 1;
}]
,["while-loop", () => {
var a = 0, l = arr.length;
while( a < l ) {
var b = arr[a] + 1;
++a;
}
}]
, ["reverse-do-while-loop", () => {
var a = arr.length - 1; // CAREFUL
do {
var b = arr[a] + 1;
} while(a--);
}]
, ["forEach", () => {
arr.forEach( a => {
var b = a + 1;
});
}]
, ["for const..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( const a in ar ) {
var b = a + 1;
}
}]
, ["for let..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( let a in ar ) {
var b = a + 1;
}
}]
, ["for var..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( var a in ar ) {
var b = a + 1;
}
}]
, ["Duff's device", () => {
var len = arr.length;
var i, n = len % 8 - 1;
if (n > 0) {
do {
var b = arr[len-n] + 1;
} while (--n); // n must be greater than 0 here
}
n = (len * 0.125) ^ 0;
if (n > 0) {
do {
i = --n <<3;
var b = arr[i] + 1;
var c = arr[i+1] + 1;
var d = arr[i+2] + 1;
var e = arr[i+3] + 1;
var f = arr[i+4] + 1;
var g = arr[i+5] + 1;
var h = arr[i+6] + 1;
var k = arr[i+7] + 1;
}
while (n); // n must be greater than 0 here also
}
}]];
function bench(title, f) {
var t0 = performance.now();
var res = f();
return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
// Here if you forget to put 'var' so variables'll be global
for(a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
});
var times = benches.map( function(a) {
arr = new Array(11111111).fill(255);
return [a[0], bench(...a)]
}).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
`<div>` +
`<span>${title} </span>` +
`<span style="width:${3+n/2}%"> ${Number(time.toFixed(3))}msec</span>` +
`</div>`;
var strRes = times.map( t => template(...t) ).join("\n") +
`<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div { clear:both }
body > div > div > span {
float:left;
width:43%;
margin:3px 0;
text-align:right;
}
body > div > div > span:nth-child(2) {
text-align:left;
background:darkorange;
animation:showup .37s .111s;
-webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>
如果顺序不重要,我更喜欢这种风格:
for(var i = array.length; i--; )
它缓存长度并且写入要短得多。但它会以相反的顺序遍历数组。