使用 var 声明的迭代变量会渗透到循环体外部:
for (var i = 0; i < 5; i++) {
// 循环逻辑
}
// 5
console.log(i);
改成 let 后,这个问题就消失了,因为迭代变量的作用域被限制在了循环体内部:
for (let i = 0; i < 5; i++) {
// 循环逻辑
}
// 找不到名称“i”。
console.log(i);
使用 var 声明的迭代变量还有一个问题是:
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 预期:0、1、2、3、4
// 实际:5、5、5、5、5
在退出循环时,迭代变量保存的是导致循环退出的值,在之后执行 setTimeout 时,所有的 i 都是同一个变量,因此最终输出的是同一个值。
如果使用的是 let 声明的迭代变量,JavaScript 会在后台为每个迭代循环声明一个新的迭代变量,它们各自独立,所以 setTimeout 中引用的都是不同的变量实例,所以 console.log 会输出我们期望的值。
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 打印 0、1、2、3、4
这种每次迭代声明一个新的变量实例的风格适用于所有的 for 循环,包括 for…in 和 for…of 循环
引用信息
- MDN Web 开发者文档
- JavaScript 高级程序设计(第4版)