简体   繁体   English

为什么/ setTimeout()代码实际上输出0到9之间的数字?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM