suchen

Heim  >  Fragen und Antworten  >  Hauptteil

javascript – Der erste Parameter von setTimeout besteht darin, die Funktion sofort auszuführen, ich kann es nicht verstehen

Der erste Parameter von setTimeout besteht darin, die Funktion sofort auszuführen, ich kann es nicht verstehen

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

Obwohl das Ergebnis sofort 0,1,2,3,4 ausgibt, weiß ich nicht warum

大家讲道理大家讲道理2702 Tage vor982

Antworte allen(9)Ich werde antworten

  • 给我你的怀抱

    给我你的怀抱2017-07-05 10:58:26

    这样其实是一下子全部打印出来的。。。不是每隔一秒打印出来。。建议这样写。。

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

    我来解释一下这个为什么可以获取到0、1、2、3、4.
    网上关于JS预解释的文章也不少,在进入执行上下文阶段的时候函数并不会执行,简单来说就是当你声明这个函数的时候,只要不调用就不会执行,上下文里面只会保存着这个函数的引用,可以看做这个函数保存在内存中,只有到调用的时候函数才会执行,我说说自己的理解,有不对的地方请指出来。
    如果没有立即执行函数:
    你在for循环里面实际上相当于定义了5个定时器,但是js是单线程,这五个函数会被放到队列里面等待执行,举个不一定恰当的例子,你就把这五个函数function() {console.log(i);}当成字符串保存到内存中,一直没什么动静,等到这五个函数调用执行的时候(就是setTimeout的第二个参数的时间到了的时候),才会开始执行这个函数,因为函数里面有个i,这个时候会通过作用域链来查找这个i,最后在外面的作用域里面查找到了i,但是这个时候for循环已经执行结束了,i已经变成4了,所以会打印出5个4.
    如果有立即执行函数(比如我上面写的那个):
    你在for循环里面实际上相当于定义了5个定时器,但是js是单线程,这五个函数会被放到队列里面等待执行。

    (function(i) {

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

    })(i)

    但是由于外面是立即执行函数,所以会立即就执行了,并且把i传了进去,等到这五个函数执行的时候,向上查找i,正好在这个立即调用函数的作用域里面查找到了i,所以会打印出0、1、2、3、4.

    Antwort
    0
  • 大家讲道理

    大家讲道理2017-07-05 10:58:26

    你先看括住整个function的那个括号
    也就是:

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

    这一段,理解就是把自己包成一个包裹,是一个整体,这个整体是一个函数

    那么接下来怎么调用函数呢?是不是函数名()这样,在函数名后面加上括号,并且可以传递参数进去

    所以很自然的,就出现了这样:

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

    这种调用,就是写个函数,用()包起来,在后面接个(),里面写参数,就直接执行了

    Antwort
    0
  • 为情所困

    为情所困2017-07-05 10:58:26

    就像楼上说的是立刻打印出来了,你的setTimeout根本就没起作用。
    原因就是立即执行函数执行后没有返回值,所以相当于setTimeout(undefined, i*1000)。

    Antwort
    0
  • 迷茫

    迷茫2017-07-05 10:58:26

    setTimeout要求第1个参数是一个函数,这样等第2个参数规定的时间到了之后,开始执行第1个参数定义的函数。

    当你这么写的时候:

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

    你会注意到定时器已经起作用了,只不过是每隔1秒种打出来一个undefined。因为当执行这个函数的时候,i已经从循环中跳出,已经没有值了。

    所以你改成这样:

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

    但在这种情况下,第1个参数不是一个函数,而是一个表达式,也就是说会立即执行的函数,它不会等到计时器起作用才执行,而是只要一碰到就会执行,所以表现形式就是直接打出了0,1,2,3,4。

    按照楼上的说法改成这样:

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

    虽然第1个参数是一个表达式,还是会立即执行,但是这个表达式执行的结果不是输出数值,而是返回一个函数,这就满足了setTimeout对第1个参数是函数的要求,并且给定了正确的输入参数,所以每隔1秒种会输出一个正确的结果。

    不过,为了团队协作起见,我一般不建议这么写,我建议还是规规矩矩按照setTimeout的标准写法写成这样:

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

    这样至少对于组内其他成员读起来更容易理解一些。

    Antwort
    0
  • 我想大声告诉你

    我想大声告诉你2017-07-05 10:58:26

    因为是立即执行的函数啊,当然立即输出了

    Antwort
    0
  • 淡淡烟草味

    淡淡烟草味2017-07-05 10:58:26

    函数作用域问题,改变this指向就可以了。

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

    Antwort
    0
  • 習慣沉默

    習慣沉默2017-07-05 10:58:26

    没有立即执行函数的话,打印出来的是5个5,而且是每隔一秒打印,因为这里setTimeout里面的函数要等循环完成之后才会执行,这时全局变量i就是5了。使用立即执行函数,会获取循环中的每一个i,这里有闭包的效果,这个i这时就是一个局部变量了,存在于此函数中,每次执行时变量i的值都不一样。

    Antwort
    0
  • 黄舟

    黄舟2017-07-05 10:58:26

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

    声明了马上执行 这样 就是 0 1 2 3 4

    然而这个没有返回值 因此默认是 undefined

    因此你的代码可以认为是这样:

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

    Antwort
    0
  • 黄舟

    黄舟2017-07-05 10:58:26

    • 理解一下原理,闭包,堆栈,事件队列,同步,异步

    • 翻转一下思路:把传进去的参数i去掉,看看是不是能正常打印,不能的话,分析一下为什么

    • 能不能换几种写法,实现上面一样的效果,分析一下为什么
      完成上面的几点,你就知道原因 过程 结果

    Antwort
    0
  • StornierenAntwort