输出是三次 3(假设循环条件是 i < 3)。
原因:var 声明的变量是函数作用域,整个循环共享同一个 i。绑定的回调通过闭包引用的是这个共享变量本身,而不是每次迭代的值。循环同步执行完毕后 i 已变成 3,之后点击按钮时才读取 i,自然都是 3。
for (var i = 0; i < 3; i++) {
btn[i].onclick = function () {
alert(i); // 点击时统一输出 3
};
}
修复方式:
// 方式一:let,每次迭代产生新的块级绑定
for (let i = 0; i < 3; i++) { btn[i].onclick = () => alert(i); }
// 方式二:IIFE,把当前值作为参数传进去
for (var i = 0; i < 3; i++) {
(function (j) { btn[j].onclick = () => alert(j); })(i);
}
易错点:循环体内若有 setTimeout 等异步代码,var 同样会全部输出最终值。追问:let 为什么能解决(每次迭代创建新的词法环境)。