这是因为add_row() 是异步的。当操作完成时,它会调用您稍后传递给它的回调。同时,for 循环已经完成。 ES6 中的一个简单解决方案是将let 与for 循环一起使用。这将为循环的每次运行创建一个新的单独的 i 变量,因此当稍后调用回调时,用于该循环调用的变量 i 仍处于函数启动时的位置。
如果您要像这样在代码中插入一些 console.log() 语句:
var m = 3;
console.log("A");
for (i = 0; i < m; i++) {
console.log("B" + i);
add_row('row-'+(i+1), () => {
console.log("C" + i);
f(i);
})
}
console.log("D");
您将在控制台中看到的是:
A
B0
B1
B2
D
C0
C1
C2
注意“D”如何出现在任何“Cx”行之前。这向您展示了在您的 for 循环执行完成后如何调用异步回调。
请研究一下,当您完全理解该命令的原因时,您将最终理解异步回调。从技术上讲,C0、C1 和 C2 将位于末尾,但可以以任何相对于彼此的顺序排列。
以下是如何使用let 为for 循环创建一个单独的变量i 为循环的每次迭代,这样当回调被调用一段时间时你仍然有i 的适当值稍后:
for (let i = 0; i < m; i++) {
add_row('row-'+(i+1), () => f(i))
}
在 ES6 之前,可以通过创建一个额外的闭包来解决这个问题,该闭包会创建一个新的函数作用域变量,以便为每次调用分别“记住”循环索引:
for (var i = 0; i < m; i++) {
(function(index) {
add_row('row-'+(index+1), () => f(index))
})(i);
}