JS 函数的执行规则
规则:同步优先、异步靠边、回调垫底。
- js的执行机制: js是单线程环境,从上到下、依次执行,即同步执行;for循环是同步代码setTimeout是异步代码。js在执行代码的过程中,碰到同步代码会依次执行,碰到异步代码就会将其放入任务队列中进行等待,当同步代码执行完毕后再开始执行异步代码,即异步执行。
实例一:let在for循环的外部
let i
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
结果是打印出 6、6、6、6、6、6
实例二:将var声明在for内
for(var i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
结果是打印出 6、6、6、6、6、6
打印输出6个6的原因:当同步代码(也就是for循环)执行完毕后,才会开始执行异步的setTimeout代码,因为执行setTimeout时需要从当前作用域内寻找一个变量i,此时for循环已执行完毕,得到当前 i=6,所以执行setTimeout时输出为6,任务队列中的剩余5个setTimeout也依次执行,输出为6。
实例三:将let声明在for内
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
结果是打印出 0、1、2、3、4、5
打印输出0~5的原因:
- let会单独创建一个作用域
- 即每次执行时都是一个独立的函数,执行当前代码循环时,setTimeout也作用于当前let,相当于有6个不同的i 相当于
(let i = 0) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 1) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 2) {
setTimeout(()=>{
console.log(i)
},0)
};
(let i = 3) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 4) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 5) {
setTimeout(()=>{
console.log(i)
},0)
};
打印出1~5的其他方法
- 闭包
let i
for(i = 0; i<6; i++){
!function(j){
setTimeout(()=>{
console.log(j)
},0)
}(i)
}
- 利用 setTimeout 的第三个参数,将i传进去
let i
for(i = 0; i<6; i++){
setTimeout((value)=>{
console.log(value)
},0,i)
}
- 利用 const 关键字
let i
for(i=0; i<6; i++)
{
const x=i
setTimeout(()=>{
console.log(x)
})
}