settimeout()的问题的3个疑惑点

直接附上代码:

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

运行结果是立即输出0、1、2、3、4

疑惑点:
1:在setTimeout()里面的第一个参数赋予一个立即执行函数,setTimeout的延时就不起作用了,为什么不是每隔一秒依次输出0、1、2、3、4?

2:为什么输出的不是5了,setTimeout执行的时候 for里面的i还没有变成5吗?不是setTimeout要在for执行完再执行的吗?
可以跟下面这个做比较,下面这个函数我的第三个疑惑点是:为什么第二个参数里面的1000*i 里面的i不起作用,就是为什么不是每隔5秒输出呢,因为轮到settimeout执行时,i不是已经变成5了吗?

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

运行结束时每隔一秒输出一个5,一共5个5.

希望有大牛帮忙解答这三个疑惑点,我理解的不是很到位,谢谢。

阅读 5.1k
8 个回答

你在第一个的console.log(i)下面再加一行return function (){console.log(i)}
再看看。
按照你的写法,你代码里写的是函数的调用,所以直接就调用了。然后setTimeout执行的是你调用的函数的返回值,即undefined

// 你的 第一种 写法 是 有问题 的
    for (var i = 0; i < 5; i++) {
    setTimeout((function(i) {
    console.log(i); // 这里是 循环 的 时候 立即 执行 而不是 定时器 延迟(异步) 执行 的
    return 'alert(' + i + ')'; // 改成 这样 就好 了 这样 相当于 第一个 参数 是 字符串 然后 定时器 后台 延迟 秒数 执行
    /*
    又或者 改成 
    return function(){
    alert(i); // 这样 形成 闭包 这样 相当于 定时器 第一个 参数 是 这个 内部 函数 这样 异步 执行 时 就能 访问 外部 的 函数 保存 下来 滴形参 
    };
    */
    })(i), i * 1000);
    }
    // 关于 第二种  方法 为什么 都是 5 百度 一 搜 一大堆 详细的 说明 _(:3_|/_)_

第一种情况,setTimeout函数在计数完成后会执行第一个参数,既传进去的方法,如果里面传的是立即执行的函数,在调用setTimeout的时候就会被执行。因为setTimeout是异步的,所以循环会执行即时执行函数而不用等待setTimeout。第二种情况,setTimeout是异步的,在执行第一个参数方法时,实际上循环已经走完了。

第二种情况其实是一个closure,虽然循环的时候传入的参数i的值不同,但是由于setTimeout是异步执行的,最后执行的时候当access i的时候,i已经被update成5.

//第一种相当于
for(var i=0;i<5;i++){
    (function(i){
        console.log(i);
    })(i);
}

setTimeout的第一个参数为立即执行函数,在设置定时器的时候就直接被执行。

第二种执行for循环,设置一个定时器并把当前scope的变量i传入定时器中。当定时器执行时变量i已经变成5,所以输出为5。

下面的代码可以间隔1秒输出0,1,2,3,4

for(var i=0;i<5;i++){
    setTimeout(function(i){
        return function(){
            //此时的i为外层函数的参数,为外层函数体的局部变量。
            console.log(i);
        }
    }(i), i*1000);
}
推荐问题
宣传栏