[英]Why does this for / setTimeout() code actually output the numbers from 0 to 9?
A common pitfall with JavaScript closures is running setTimeout()
from a for
loop , and expecting the counter to be passed with different values at each iteration, while in practice it gets assigned the last value before the setTimeout()
functions execute: JavaScript闭包的一个常见陷阱是, 从
for
循环运行setTimeout()
,并希望每次迭代时以不同的值传递计数器,而实际上,在setTimeout()
函数执行之前会为它分配最后一个值:
for (i = 0; i < 10; i++) { setTimeout(function () { console.log(i) }, 100); } // => prints "10" 10 times
One solution to this is to have an Immediately Invoked Function Expression: 一种解决方案是使用立即调用的函数表达式:
for (i = 0; i < 10; i++) (function(j) { setTimeout(function foo() { console.log(j) }, 100); })(i); // prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Another is to pass an extra callback argument to setTimeout()
(which doesn't work in IE<9): 另一个方法是将一个额外的回调参数传递给
setTimeout()
(在IE <9中不起作用):
for (i = 0; i < 10; i++) { setTimeout(function foo(n) { console.log(n) }, 100, i); }
But why does the following, simplest, code, produce the same result ( 0, 1, 2, ... 9
)? 但是,为什么以下最简单的代码会产生相同的结果(
0, 1, 2, ... 9
)?
for (var i = 0; i < 10; i++) setTimeout(console.log(i), 100);
This apparently surprising behavior occurs because the first parameter to setTimeout
can be a function as well as a string, the latter being eval()
-ed as code. 之所以出现这种显然令人惊讶的行为,是因为
setTimeout
的第一个参数可以是一个函数,也可以是一个字符串,后者是eval()
代码。
So setTimeout(console.log(i), 100);
所以
setTimeout(console.log(i), 100);
will execute console.log(i)
right away, which returns undefined
. 将立即执行
console.log(i)
,返回undefined
。 Then setTimeout("", 100)
will be executed, with a NOP call after 100ms (or optimized away by the engine). 然后将执行
setTimeout("", 100)
,并在100毫秒后(或由引擎优化)进行NOP调用。
Just for grins, another thing you can do (when you've got .bind()
) is 仅出于笑容,您可以做的另一件事(当您拥有
.bind()
)是
for (i = 0; i < 10; i++) {
setTimeout(function () {
var i = +this;
console.log(i)
}.bind(i), 100);
}
A little bit less of a mess than an IIFE. 比IIFE少一点混乱。
why does the following, simplest, code, produce the same result (0, 1, 2, ... 9)?
为什么以下最简单的代码产生相同的结果(0、1、2,... 9)?
for (var i = 0; i < 10; i++) setTimeout(console.log(i), 100);
Because it actually doesn't. 因为实际上没有。 If you look closely, you will notice that the log messages will not need the tenth of a second before they appear in console.
如果仔细观察,您会发现日志消息在控制台中显示之前并不需要十分之一秒。 By calling the
console.log(i)
right away, you are only passing the result of the call ( undefined
) to setTimeout
, which will do nothing later. 通过立即调用
console.log(i)
,您只是将调用结果( undefined
)传递给setTimeout
,此方法以后将不执行任何操作 。 In fact, the code is equivalent to 实际上,代码等同于
for (var i = 0; i < 10; i++) {
console.log(i);
setTimeout(undefined, 100);
}
You will notice the difference better if you replace the 100
by i*500
in all your snippets, so that the log messages should be delayed at an interval of a half second. 如果将所有代码段中的
100
替换为i*500
,您会发现更好的区别,因此日志消息应每隔半秒延迟一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.