查看此代码:
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 200);
}
这是经典的错误,它反复打印i
的最终值,而不打印所需的连续输出。
我知道可以使用let
而不是var
来解决该问题:
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 200);
}
让我困惑的是为什么这个 不能解决它:
for(var i = 0; i < 5; i++) {
setTimeout(function() {
let n = i;
console.log(n);
}, 200);
}
现在,出于与先前代码相同的原因,应对其进行修复,但该错误仍然存在。为什么会这样?
答案 0 :(得分:1)
您仍在i
回调函数中引用setTimeout
,因此仍然有一个闭包。实际上,这与您的第一个带有计时器的“经典”闭合问题的例子没有什么不同。
let
示例避免了该问题的原因是,即使在计时器回调中引用了i
,它也与早期循环迭代中的i
不同。每次迭代都有自己的i
。
答案 1 :(得分:1)
在for循环的开头,let
声明有一种特殊的行为。该变量在每次迭代中都唯一声明。这就是为什么示例2“有效”的原因。
在示例3中,var i
声明仅发生一次,并且该值在每次迭代时都会更新。 let
也在执行时声明。因此,每次在示例#3中执行回调函数时,第一次是在for循环的所有迭代都发生之后,let n = i
被声明(在执行时),此时i
是for循环中声明的单个i
。
我鼓励您快速阅读本快速入门。 https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch5.md#block-scoping-revisited
console.log(a);
var a = 10;
将打印undefined
,因为在console.log
a
时已声明但未分配。
console.log(a);
let (or const) a = 10;
将抛出TypeError
,因为在console.log
a
时尚未声明。