for循环中setTimeout的问题

for (var i = 0; i <= 3; i++) {
    setTimeout(function  () {
        console.log(i);
    },0);
}


for (var i = 0; i <= 3; i++) {
    setTimeout(function  (a) {
        console.log(a);
    }(i),0);
}

为什么结果是:
0
1
2
3
4 ,这里打印了4次
延迟的时间为0,为何先执行下面的for循环呢,为何上面的for循环打印的最终的i,下面的for循环是逐个打印呢?

阅读 13.3k
4 个回答

1.setTimeout绑定的回调函数只是往Javascript的事件循环机制中注册了一个定时器,这个定时器只可能在当前时间循环的下一次事件循环中才有可能被执行(需要检查时间是否符合设置的时间点)
2.

function  (a) {
 console.log(a);
}(i)

是一个立即执行函数,在你setTimeout函数执行调用时就被执行了,而不是等到定时器到点后被执行
3.setTimeout(fn,0)并不是立即执行的语义,只是说在下一次时间循环到达时可以马上执行
4.打印4次4的问题

for (var i = 0; i <= 3; i++) {
    setTimeout(function  () {
        console.log(i);
    },0);
}

等价==>

var i;//a
for (i = 0; i <= 3; i++) {
    setTimeout(function  () {
        console.log(i);
    },0);
}

输出4次4是因为javacript没有块作用域,只有函数作用域,一个函数在定义时其中俄变量的作用域就确定;函数中变量i的指向的a处声明的变量,在for循环结束后i的值就是4并且你定义了4个同样的定时器

function (a) {
    console.log(a);
}(i)

这个不是合法的立即执行函数吧

异步 异步 异步
重要的事儿说3次
第二个一定后打印 结果4444

为什么第二个先打印 很简单

{
    console.log(a);
}(i)

你直接执行了回调函数
就这么简单
由于 异步 所以 第一个循环 结果会后出来

首先你要理解延迟时间0的问题,其次呢,你还需要理解函数执行的问题,再次,你还要理解闭包的问题;

第一,为什么先执行了下面的for循环?

因为在你第二个for循环中的setTimeout里面不只是一个简单的匿名函数,而是你定义了一个匿名函数后就立马执行了(因为你函数定义后使用了(i)进行调用并把i当做参数传到函数里),此处立马执行的意思是代码执行到这里,这个函数就被调用了...所以就开始打印0,1,2,3

而setTimeout延迟0并不代表你使用了setTimeout之后0秒就立即执行了,如果0秒立即执行,那么会先执行setTimeout设置的延迟0所应该调用的函数然后才继续执行下面的代码,而此处0是指设定一个任务,当现有的任务执行完了之后延迟0(若有设置时间则延迟相应的时间)开始执行,所以此处会先执行完现有的代码之后才会执行所谓的延迟0的那个该调用的函数

这样谁先谁后就很明了了

第二,为什么上面的for循环打印的是最终的i?

结合第一点,那些你在第一个for循环里逐次设定的延迟0的回调函数都是在这里所有代码都执行完了之后才执行的,那么那时候i这个变量经过了第二个for循环的遍历之后已经变成了4,因为这里的所有的变量i都是使用的同一个,所以这时候才执行的function里所取到的i已经都是4了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏