这是我在segmentfault上看到的一个问题。原问题链接
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
问题
其实我们想得到的结果是1,2,3,4,5,结果却是五个6
执行结果
每隔1秒 输出 i 为6
原因
输出i 为什么为6
JS处理时用的是队列,所以在for循环里只是把每个setTimeout任务添加到队列里,等for循环执行完之后,再去执行setTimeout函数,而此时的i变成了6,所以i输出为6,这是i 为6的理解
为什么会每隔一秒执行
刚进入for循环的时候,i为1,所以相对于现在延迟一秒将timer函数添加到队列当中,然后for循环还要继续啊,并没有等一秒再继续循环啊,然后进行第二次循环,这时候i为2,所以相对于现在延迟两秒将timer函数送进队列。以此类推。for循环的时间忽略不计的话,timer函数就以每秒一次的频率执行啦。
解决办法
- 办法1
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
//用闭包来解决:通过一个立即执行函数,为每次循环创建一个单独的作用域
- 办法2
//把var 改为let,let 每次都会创建一个块级作用域
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
- 办法3
//类似于方法二,使用setTimeout的第三个参数直接传参
for (var i = 1; i <= 5; i++) {
setTimeout(function(i) {
console.log(i);
}, i * 1000,i);
}
办法1用闭包解决,办法2用作用域解决,办法三不常见,但使用的是setTimeout的第三个参数直接传参,对第三个参数不了解的看这里
每天都努力一点点
谢谢你看完
网友评论