如何将值传递给javascript中的回调

时间:2017-07-10 12:21:16

标签: javascript closures v8

我想了解javascript引擎如何以及何时将值传递给回调函数,我已尝试调试并在线查找但我无法找到确切的答案,请考虑以下示例:

for(var i = 0; i < 4; i++) {
    console.log("outside callback " + i + " ");

    setTimeout(function test(){
      console.log("inside callback " + i + " ");
    },100);
}

打印输出

  

外部回调0

     

外部回调1

     

外部回调2

     

外部回调3

     

内部回调4

     

内部回调4

     

内部回调4

     

内部回调4

如果我只是使用let关键字更改i变量的声明,如下所示:

for(let i = 0; i < 4; i++) {
    console.log("outside callback " + i + " ");

    setTimeout(function test(){
       console.log("inside callback " + i + " ");
    },100);
}

它产生以下输出:

  

外部回调0

     

外部回调1

     

外部回调2

     

外部回调3

     

内部回调0

     

内部回调1

     

内部回调2

     

内部回调3

在Chrome中进行调试时,它在第一个示例中显示i作为第二个示例中的测试函数和块范围的闭包范围。

2 个答案:

答案 0 :(得分:2)

这涉及一个关于JavaScript closure inside loops – simple practical example的常见问题,该问题详细说明了为什么在循环中创建内部回调函数,使用var声明的变量具有循环结束时达到的值:虽然设置回调时它们可能保持不同的值,但是当执行回调时,异步,一段时间之后,循环已经很久完成并且将变量保留在闭包内,并且具有当它们保持的值时循环完成。

从ECMAScript版本6开始,使用let声明的变量是块作用域的,不能在定义它们的代码块之外访问。 另外for循环控制语句中定义的变量会受到特殊处理。

  1. 它们的范围是for循环体的范围,而不是包含for循环的代码块。
  2. 为循环的每次迭代创建let变量的新绑定。这意味着每次迭代都可以拥有自己的一组变量值,这些变量值保存在为迭代创建的词法环境记录中,可以在闭包中使用,并由循环内定义的回调函数访问。

  3. 每个词汇环境记录中的循环计数器的值旨在使多个环境记录的使用在很大程度上透明:

    for( part1; part2; part3) {
        // loop body code
    }
    
    • 在第一次迭代中,let语句中的for个定义变量具有执行part1part2后的值。
    • 在后续迭代中,它们通过将当前迭代的环境记录中的值初始化为上一次迭代结束时的值,然后执行part3part2来确定值。在上面的for声明中。
    • 回调for循环体内声明的函数,访问设置回调的迭代的 end 中保存的let定义变量的值, 排除评估part3声明for的副作用。

答案 1 :(得分:1)

实际上是因为使用let和var声明了varaibles的范围,而不仅仅是javascript的closure属性。