我想了解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作为第二个示例中的测试函数和块范围的闭包范围。
答案 0 :(得分:2)
这涉及一个关于JavaScript closure inside loops – simple practical example的常见问题,该问题详细说明了为什么在循环中创建内部回调函数,使用var
声明的变量具有循环结束时达到的值:虽然设置回调时它们可能保持不同的值,但是当执行回调时,异步,一段时间之后,循环已经很久完成并且将变量保留在闭包内,并且具有当它们保持的值时循环完成。
从ECMAScript版本6开始,使用let
声明的变量是块作用域的,不能在定义它们的代码块之外访问。 另外在for
循环控制语句中定义的变量会受到特殊处理。
for
循环体的范围,而不是包含for
循环的代码块。为循环的每次迭代创建let
变量的新绑定。这意味着每次迭代都可以拥有自己的一组变量值,这些变量值保存在为迭代创建的词法环境记录中,可以在闭包中使用,并由循环内定义的回调函数访问。
每个词汇环境记录中的循环计数器的值旨在使多个环境记录的使用在很大程度上透明:
for( part1; part2; part3) {
// loop body code
}
let
语句中的for
个定义变量具有执行part1
和part2
后的值。part3
和part2
来确定值。在上面的for
声明中。for
循环体内声明的函数,访问设置回调的迭代的 end 中保存的let
定义变量的值, 排除评估part3
声明for
的副作用。答案 1 :(得分:1)
实际上是因为使用let和var声明了varaibles的范围,而不仅仅是javascript的closure属性。