var的时候
<script>
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
console.log(' i : ', i)
}
</script>
因为setTimeout
是异步的事件。所以会先执行for的循环。
console.log('i:',i)
因为在for的作用域内部,所以可以循环打印出i
。
循环之后,就要执行setTimeout
了。
此时会输出:
这是为什么呢?为什么不会输出 0,1,2,3,4呢?
- 因为
var
,尽管var
在for里面声明了i
,但是var
会把i
泄露为全局变量。所以,循环结束不会保存0,1,2,3,4。只保存了保存5
。 - 接着再执行
setTimeout
,这个函数的作用域里没有声明i
,所以会沿着作用域链向上寻找上一级的i
。发现了全局作用域的i。此时的i = 5
,所以直接把5拿到并且5次输出。
在for外面添加console.log(i)
<script>
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
console.log(' i : ', i)
}
console.log(i)
</script>
结果输出一个5
。其实上面已经说了,var会把i泄露为全局变量。所以,循环结束不会保存0,1,2,3,4
。只保存了保存5
。console.log(i)
里的i
会先寻找本作用域的i
,所以输出5
。
let的时候
<script>
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
console.log(' i : ', i)
}
// console.log(i)
</script>
把var
换成let,let会生成一个局部的作用域。每循环一次,它就产生一个作用域。
所以,除了正常的循环打印出
console.log(' i : ', i)
外,setTimeout里面还会循环打印出0,1,2,3,4
来。
在for外面加上一个console.log(i)
<script>
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
console.log(' i : ', i)
}
console.log(i)
</script>
会报错:i is not definded
。因为for有它自己的作用域。而console.log(i)是处于另外一个作用域。
网友评论