javascript 中如何将值传递给回调

how values are passed to callbacks in javascript

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

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

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

这将打印以下输出

outside callback 0

outside callback 1

outside callback 2

outside callback 3

inside callback 4

inside callback 4

inside callback 4

inside callback 4

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

for(let i = 0; i < 4; i++) {
    console.log("outside callback " + i + " ");
    
    setTimeout(function test(){
       console.log("inside callback " + i + " ");
    },100);
}

结果如下:

outside callback 0

outside callback 1

outside callback 2

outside callback 3

inside callback 0

inside callback 1

inside callback 2

inside callback 3

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

其实是因为varaibles的作用域是用let和var声明的,而不仅仅是javascript的闭包属性。

这与有关 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
    }
    
    • 在第一次迭代中,letfor 语句中定义的变量具有它们在执行 part1part2.
    • 后的值
    • 在随后的迭代中,它们的值是通过将当前迭代的环境记录中的值初始化为上一次迭代结束时的值来确定的,然后执行 part3part2 在上面的 for 语句中。
    • for 循环体内声明的回调函数访问在调用迭代的 结束 处保存的 let 定义变量的值back 已设置,排除 计算 for 语句的 part3 的副作用。