for(var i = 1; i <= 3;i++){
setTimeout(function(){
console.log("这是上面的i:"+i)
},0)
console.log("这是下面的i:"+i)
}
输出:
OK!为啥输出结果是这样子的呢?
所用知识点:作用域,闭包,异步
相信大家对for循环已经很了解了,应该只是对setTimeout有点陌生
setTimeout(function(){
console.log(2)
},0)
console.log(1)
输出 1,2
由此可见,我们使用setTimeout的时候是一种异步机制。setTimeout有两个参数,第一个是函数,第二个是执行的时间间隔值,默认毫秒。异步指的是当函数在执行这个事件时,把函数的参数放在事件对列中,等主程序执行完,然后再执行这个事件。体现在我们的例子中,就是当程序执行到setTimeout时,会将setTimeout中的参数放在主程序执行的事件队列里,当主程序执行完毕之后,才会执行setTimeout中的内容。
当setTimeout的时间为0代表等待主程序执行完之后再执行异步的程序,若不为o则代表执行主程序的同时开始计时,等时间到了之后再执行程序。
接下来分析一下代码运行流程:
i = 1
console.log("这是下面的i:"+i) // 1
i++
console.log("这是下面的i:"+i) // 2
i++
console.log("这是下面的i:"+i) // 3
i++
console.log("这是上面的i:"+i) // 4
console.log("这是上面的i:"+i) // 4
console.log("这是上面的i:"+i) // 4
那么到这一步应该对这个理解了吧。
还有一个问题就是作用域。如果我们执行的程序是这样子的
for(let i = 1; i <= 3;i++){
setTimeout(function(){
console.log("这是上面的i:"+i)
},0)
console.log("这是下面的i:"+i)
}
输出:
这是下面的i:1
这是下面的i:2
这是下面的i:3
这是上面的i:1
这是上面的i:2
这是上面的i:3
变量提升:使用var时候声明变量是函数作用域,作用在全局,在预解析时会将变量提升到函数顶部,在这里也就是全局的顶部,而let声明的变量是块级作用域,在预解析时候会把变量提升在for循环的第一行。
代码分析:
for(let i = 1; i <= 3;i++){
let i = 圆括号中的值
setTimeout(function(){
console.log("这是上面的i:"+i)
},0)
console.log("这是下面的i:"+i)
}
// 执行流程
// 每次输出i的值,i都会根据作用域链去找他的值。
// 第一次
let i = 1
setTimeout(function(){
console.log("这是上面的i:"+i)
},0)
console.log("这是下面的i:"+i)
i++
// 第二次
let i = 2
setTimeout(function(){
console.log("这是上面的i:"+i)
},0)
console.log("这是下面的i:"+i)
i++
// 第三次
let i = 3
setTimeout(function(){console.log("这是上面的i:"+i)},0)
console.log("这是下面的i:"+i)
i++
--------------------
然后在这里呢,我们会看到setTimeout中的i依次为1,2,3 只是在每次执行的时候都将setTimeout
中的值放在了主程序之后,所以我们会输出1,2,3,1,2,3这样的结果
关于let和var在for循环中的表现可以参考以下链接:
https://blog.csdn.net/wlk2064819994/article/details/79772388
当然如果我们想要让setTimeout中的值先输出也可以,将函数改为立即执行函数
for(var i = 1; i <= 3;i++){
setTimeout(function(){
console.log("这是上面的i:"+i)
}(i),0) // 立即执行函数
console.log("这是下面的i:"+i)
}