2021 更新
var
曾经是声明变量的唯一方法。但是我们现在拥有const
并let
以更好的方式解决了这个问题。这些变量声明确实将循环视为要绑定的范围,这意味着以下代码段可以正常工作,并且不需要匿名函数来捕获这些值。
const colors = ['green', 'blue', 'red'];
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
setTimeout(function() {
alert(color);
}, i * 1000);
}
以下是我在 2012 年对这个问题的原始回答。
当您有没有立即执行的内部函数时,作为循环的一部分。
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
var color = colors[i];
setTimeout(function() {
alert(color);
}, i * 1000);
}
// red
// red
// red
即使var color
在循环内部,循环也没有范围。实际上,每个循环迭代都使用一个变量。因此,当超时触发时,它们都使用相同的值,即循环设置的最后一个值。
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
(function(color) {
setTimeout(function() {
alert(color);
}, i * 1000);
})(colors[i]);
}
// green
// blue
// red
这个将每次迭代的值捕获到函数的参数中,这确实创建了一个范围。现在每个函数都有自己的变量版本,该color
变量在以后执行该循环中创建的函数时不会改变。