由于js是单线程,所以同一时间只能做一件事情。js for循环里的定时器你需要知道的一些事。
for(var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
});
}
//打印结果5,5,5,5,5
这段代码里输出的结果是5,5,5,5,5
那么为什么是5个5呢?为什么不是0,1,2,3,4?
这是因为在所有同步代码执行完毕之后,for循环里的i值早已变成了5,循环已经结束。(注意,for循环的圆括号部分也是同步代码)
这就是为什么打印出来5个5,而不是0,1,2,3,4。
那如何打印出0,1,2,3,4呢?
第一种:使用立即执行函数,利用闭包的原理,闭包使一个函数可以继续访问它定义时的作用域。而这个新生成的作用域将每一次循环的当前i值单独保存了下来。
for(var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function () {
console.log(i);
});
})(i)
}
//打印结果0,1,2,3,4
第二种:let关键字、块作用域,let关键字劫持了for循环的块作用域,产生了类似闭包的效果,并且在for循环中使用let来定义循环变量还会有一个特殊效果:每一次循环都会重新声明变量i,随后的每个循环都会使用上一个循环结束时的值来初始化这个变量i。但是它是ES6语法,在低版本中无法使用。
for(let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
});
}
//打印结果0,1,2,3,4
第三种:使用try...catch语句,try...catch语句的catch后面的花括号是一个块作用域,和let的效果一样。所以在try语句块里抛出循环变量i,然后在catch的块作用域里接收到传过来的i,就可以将循环变量保存下来,实现类似闭包和let的效果。
for(var i = 0; i < 5; i++) {
try {
throw(i)
} catch(j) {
setTimeout(function () {
console.log(j);
});
}
}
//打印结果0,1,2,3,4
END