调用时机 一个函数调用时机不同 他的结果就不同
问题:解释如下代码为什么是6个6
let i=0
for(i=0;i<6;i++){
setTimeout(()=>{
console.log(i)
},0)
}
问打印出多少?
6个6
原因:
setTimeout
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成。它们向任务队列添加定时任务。
setTimeout 允许我们将函数推迟到一段时间间隔之后再进行执行,它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。
let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
func|code
是将要推迟执行的函数名或者一段代码
delay
是推迟执行的毫秒数
arg1
是推迟执行毫秒数之后回调函数执行时,作为回调函数的参数。
返回值timeoutID
是一个正整数,表示定时器的编号。这个值可以传递给clearTimeout()
来取消该定时器。
在代码中看起来代码的顺序应该好像是从上往下依次执行,但其实不是的。
在js
执行过程中,当同步和异步代码同时存在时,异步代码会在同步代码全部执行完成后再调用。而setTimeout
就是异步代码(就算延迟为零也是异步),它会在代码最后执行,因此执行顺序为先进行for循环。最后才执行setTimeout这时候的i已经经过自增变成了`6,所以最后输出的结果为6个6。
另外值得注意的是setTimeout存在优先级的问题,setTimeout
会在指定时间后触发。如果同步代码执行时间大于setTimeout设定时间,那么它将在其他代码执行完成后立即执行。
那么如何实现能让它打出我们想要的 0,1,2,3,4,5,呢?
利用let形成块级作用域
for(let i=0;i<6;i++){
setTimeout(()=>{
console.log(i)
},0)
}
其他方法:参考来自知乎
一、建立闭包
for (var i = 0; i < 6; i++) {
(function(index) {
setTimeout(function() {console.log(index)}, i * 1)
})(i)
}
因为 Javascript 只有两种作用域,一是全局作用域,二是函数作用域,它是没有块级作用域的
所以闭包的出现就相当于利用一个匿名函数的壳模拟出一个块级作用域
上述代码块往匿名函数内部传的参数将会被拷贝一份,也就是说循环没执行一次就拷贝变量 i 的值到匿名函数内部
for (let i = 0; i< 6; i++){
setTimeout((()=>console.log(i))(),0);
}