函数的执行时机不同,运行结果也不同。
let i = 0;
for(i; i<6; i++){
setTimeout(() => {
console.log(i)
}, 0)
}
上述代码会打印出6个6。这里的关键就是在setTimeout函数,setTimeout函数用来指定某个函数或某段代码,在多少毫秒后执行。但为什么会打印出6个6的情况呢?
可以这么理解:
- JS是单线程的,单线程就意味着所有任务需要排队,当前任务结束后,才会执行下一个任务,通常我们把这种称之为同步任务。
- 异步任务:规划要做一件事情,但不是当前立马去执行这件事情,需要等待一定时间,那么我们不会等待这个任务执行完毕(即阻塞),而是直接执行下面的操作。
setTimeout函数就是用来指定一个异步任务,当代码执行到这里,会把异步任务放到任务队列当中,等到JS引擎线程空闲,才会依次解决任务队列里的异步任务。
上述代码中因为循环了6次,每执行一次就将异步任务放入到任务队列当中,当循环执行完毕,i的值为6,再执行任务队列里的6个任务,所以会打印出6个6。
如何依次打印出i的值
如果不了解异步任务这一概念,就会觉得上述代码非常反直觉。如果就是要打出0,1,2,3,4,5,可以这么解决:
for(let i=0; i<6; i++){
setTimeout(() => {
console.log(i);
}, 0)
}
输出如下
这里在循环体中定义i,它的作用域只在这个块级作用域,且当前的i只在当前循环中有效,所以每一次循环的i其实是一个新变量。
虽然每一轮循环时i都会重新声明,但是JS内部引擎会记住上一轮循环的值,然后复制了一个i的值,在初始化上一轮变量i的同时,保证了下一轮循环可以在上一轮循环的基础上进行计算,每次循环的i其实都是一个新的变量。
其他方法
方法一:利用const关键字
let i = 0;
for(i; i<6; i++){
const x = i;
setTimeout(() => {
console.log(x);
}, 0)
}
方法二:利用setTimeout函数的第三个参数,传入i
let i = 0;
for(i; i<6; i++){
setTimeout((value)=>{
console.log(value)
},0,i)
}