提倡let语句在for
循环中用作替换var
迭代变量的声明。
通过使用let
,用户可以放弃使用立即调用功能
例如,为回调保留迭代变量的值。
来自mdn:
var list = document.getElementById('list');
for (let i = 1; i <= 5; i++) {
let item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));
item.onclick = function(ev) {
console.log('Item ' + i + ' is clicked.');
};
list.appendChild(item);
}
// to achieve the same effect with 'var'
// you have to create a different context
// using a closure to preserve the value
for (var i = 1; i <= 5; i++) {
var item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));
(function(i){
item.onclick = function(ev) {
console.log('Item ' + i + ' is clicked.');
};
})(i);
list.appendChild(item);
}
如果我在循环结束时更新迭代变量i
,for
结构将拾取它并在循环的comperator逻辑中使用新值并将该值传递给下一次执行该块。
console.log("start");
for (let i = 0; i < 5; i++) {
console.log("in loop", i);
setTimeout(function () {
console.log(i);
}, 0);
i = i + 2;
}
console.log("end");
结果:
start
in loop 0
in loop 3
end
undefined
2
5
第二次迭代中的更改,不会传播到第一次迭代超时回调。
目前,for
循环实现为每次迭代创建一个块执行上下文,将迭代变量作为参数传递,并在块执行结束后专门提取其值并在{{1下一次迭代的机制。但知道这是否属实以及如何实施将会很有趣。
答案 0 :(得分:1)
没有太多可说的。你的观察是正确的。每次迭代都有一个单独的块。所以,无论你的超时有多长,你都会看到相同的结果。
在每次迭代结束时,i
的值将传递给下一次迭代。由于i
不是对象,因此不会通过引用传递。因此,在下一次迭代中i的修改/增量不会影响前一次迭代块中i
的值。
只是为了好玩,尝试使用对象而不是原始数字:
console.log("start");
for (let i = {i:0}; i.i < 5; i.i++) {
console.log("in loop", i.i);
setTimeout(function () {
console.log(i.i);
}, 0);
i.i = i.i + 2;
}
console.log("end");
结果:
start
in loop 0
in loop 3
end
undefined
6
6
如您所见,在这种情况下,您的i.i
变量实际上将通过引用传递,因此您可以在不同的迭代块上修改它。