setTimeout函数之循环和闭包

所有的时光都是被辜负被浪费后,才能从记忆里将某一段拎出来,拍拍上面沉积的灰尘,感叹它是最好的时光。

代码片段一

1
2
3
4
5
for (var i = 0 ; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}

结果:

在控制台下, 一秒后输出5个5, 没有时间间隔;

分析:

setTimeout的执行异步的, for 循环的执行是很快的, 当setTimeout开始执行的时候,for循环已经执行完毕, 此时的i变为5(for循环使用var申明的变量是全局的), 因为所有的都是延迟1S执行, 所以最后一起输出;

代码片段二

1
2
3
4
5
for (var i = 0 ; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}

结果:

在控制台下, 每隔一秒输出一个5;

分析:

为什么是5, 上一个代码片段已经分析, 每一秒输出一个的原因就是for循环过程中调用setTimeout的时候,调用5次时间非常短可忽略不计, 调用依次给的延迟秒数是0s,1s,2s,3s,4s.所以我们再最后看到他执行的时候, 是每隔一秒出现一个;

代码片段三

1
2
3
4
5
6
7
for (var i = 0 ; i < 5; i++) {
(function () {
setTimeout(function () {
console.log(i);
}, i*1000);
})();
}

结果:

在控制台下, 每隔一秒输出一个5, 和代码片段二的结果一样;

分析:
虽然加了闭包, 但是并没有影响结果

代码片段四

1
2
3
4
5
6
7
for (var i = 0 ; i < 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, i*1000);
})(i);
}

结果:

在控制台下,每隔一秒依次输出0,1,2,3,4;

分析:
此时setTimeout里面的参数是通过闭包传递的, 并没有受到全局i的影响

代码片段五

1
2
3
4
5
6
7
for (let i = 0 ; i < 5; i++) {
(function () {
setTimeout(function () {
console.log(i);
}, i*1000);
})();
}

结果:

在控制台下,每隔一秒依次输出0,1,2,3,4;

分析:

使用let申明的变量是块级作用域, 当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量;

更多关于let var 的区别, 请参考我的另外一篇文字: var,let,const的区别