?
直接上代码!
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
这个代码按照我们的逻辑来讲,先让i=0,让后for循环依次打印出i的值来,直到不满足i<6这个条件,并且打印的时间间隔为0秒。
咳咳,按照逻辑来讲,系统应该会依次打印出0、1、2、3、4、5这六个值,可是实际结果却并不是这样的

可以看出,这段代码打印出来的居然是6个6!这究竟是为什么呢?
逻辑错了吗?这个其实逻辑没有错,但是底层代码的实现过程相对于我们人而言其实是透明的,机器会严格按照代码的顺序来实现,我们逻辑上的0秒与系统底层的0秒其实是不同的。逻辑上的0秒是完全理想的0,而实际代码执行中只能无限接近0秒这个时间间隔,然后很不幸,系统处理代码是很快的(对于我们而言是透明的),在这个无限接近0秒的时间间隔中,代码已经执行完6次了,i停在了i=6这儿,然后执行延迟0秒的代码console.log(i)。
JS函数的执行时机其实还是代码的实现顺序,机器是不会有错的!(个人理解,有错望各位指正!)
!
那么其实问题又双叒来了,我要怎么才能让i顺序输出0、1、2、3、4、5来呢?试试下面这段代码吧!
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
哇!居然又能打印顺序打印出了呢!

这个其实是和for+let声明变量有一个特殊的行为,这个行为指出变量在循环过程中不止被声明一次,每次迭代都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
但是不止有上面这一种方法实现打印出0、1、2、3、4、5的方法,下面三种也可以
- 引入IIFE(立即执行函数)
let i = 0
for(i = 0; i < 6; i++){
(function(i){
setTimeout(()=>{
console.log(i)
},0)
})(i)
}
- 利用setTimeout的第三个参数
let i = 0
for(i = 0; i < 6; i++){
setTimeout((j)=>{
console.log(j)
},0,i)
}
setTimeout()如果想给回调函数传递参数,直接在第二个参数delay后面加上附加的参数。
参考语法var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...]);
- 利用闭包
let i = 0
for(i = 0; i < 6; i++){
setTimeout(((j) => {
return ()=>{
console.log(j)
}
})(i),0)
}
如果大家还有其他的方法,欢迎留下,一起交流。