有人可以清楚地分解这里发生的事情吗?
function timerCheck() {
for(var i=0; i<5; i++) {
setTimeout(function() {
console.log("Hello" + i);
}, 3000);
}
}
因此,有些人可能知道,调用此函数将无法按预期工作。最终会发生的是,这个函数将一次调用5次,每次设置为5。这将是3秒后的输出:
Hello5
Hello5
Hello5
Hello5
Hello5
我也明白使用setInterval方法是解决这类问题的正确方法,但我很好奇这里发生了什么。我真的想了解Javascript的工作原理。请注意,我没有计算机科学背景,只是一个自学成才的编码器。
答案 0 :(得分:2)
这可能有助于您更好地了解正在发生的事情:
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中立即执行。 IE浏览器。 (function(x){ console.log(x); })('Hi');
将Hi
打印到控制台。所以上面的外部函数只接受一个参数(i
的当前值)并将其存储到名为loc_i
的函数的局部变量中。该函数立即返回一个将"Hello" + loc_i
打印到控制台的新函数。这是传递给超时的函数。
我希望一切都有意义,如果你还不清楚某事,请告诉我。
答案 1 :(得分:1)
JavaScript中的变量范围仅限于函数。
在您的示例中,变量i
在timerCheck
内声明。这意味着在循环结束时,i
将等于5
。
现在,添加对setTimeout
的调用不会改变i
的作用域为timerCheck
且i
已修改为{{1}的事实到每个5
调用中的代码运行时。
您可以创建一个“捕获”setTimeout
值的函数,这样当您从循环内部调用它时,您将获得i
调用的新变量范围:
setTimeout
由于function createTimer(j) {
setTimeout(function() {
console.log("Hello" + j);
}, 3000);
}
function timerCheck() {
for(var i=0; i<5; i++) {
createTimer(i);
}
}
采用参数createTimer
,当您将j
从i
中的for循环传递到timerCheck
时,createTimer
为现在限定为j
,以便每个createTimer
调用都有自己的setTimeout
。
答案 2 :(得分:0)
这实际上是安德鲁斯回答的补充
如果您尝试设置一个设置输出的变量,它也会解释范围。
function test()
{
for(var i=0; i<5; i++) {
t = "Hello " + i + "<br/>";
document.write(t);
setTimeout(function() {
document.write(t);
}, 3000);
}
}
正如您所看到的那样,写入将按预期进行,但在setTimeout触发时,t变量将是最后一次设置。哪个是Hello 4.
所以输出将是
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
来自循环和
Hello 4
Hello 4
Hello 4
Hello 4
Hello 4
来自setTimeout 的