这可能有助于更好地理解发生了什么:
function timerCheck() {
for(var i=0; i<5; i++) {
console.log("Hi" + i);
setTimeout(function() {
console.log("Hello" + i);
}, 3000);
console.log("Bye" + i);
}
}
您会看到
Hi0
Bye0
Hi1
Bye1
Hi2
Bye2
Hi3
Bye3
Hi4
Bye4
立即打印到控制台,因为循环的所有五次迭代都非常快地完成,然后在五秒钟后您将看到:
Hello5
Hello5
Hello5
Hello5
Hello5
因为超时时间(所有的超时时间几乎同时设置)都在一起发生,而且由于循环已经完成:i == 5。这是由于i的作用域引起的。变量i在timerCheck()中声明后,其范围在任何地方都可以使用。在setTimeout设置的匿名函数中没有局部i,也没有var i,并且i没有作为参数传递给函数。您可以通过闭包轻松解决这个问题,这将返回一个具有i的本地副本的函数:
function timerCheck() {
for(var i=0; i<5; i++) {
setTimeout((function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i), 3000);
}
}
这将输出:
Hello0
Hello1
Hello2
Hello3
Hello4
为了理解这个问题:
(function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i)
你需要知道,在Javascript中,函数可以立即执行。例如:
(function(x){ console.log(x); })('Hi');
会在控制台打印出
Hi
。因此,上述外部函数只是接受一个参数(
i
的当前值),并将其存储到该函数的本地变量
loc_i
中。该函数立即返回一个新函数,该函数将
"Hello" + loc_i
打印到控制台。这就是传递给超时函数的函数。
希望这一切都讲得很清楚,如果您还有疑问,请告诉我。