问题描述
我检查了关于同一问题的问题和答案,但没有人回答我的问题,所以请不要丢弃我的问题。
当 "i" 被声明为 let 变量时,对于每次迭代,JS 都会创建一个新的 "i" 绑定, 因此,SetTimout 的每个函数在其闭包中都有自己的“i”(与将“i”声明为 var 变量的情况相反,其中所有 SetTimout 函数在其闭包中共享相同的绑定)。 问题是 : 如果JS在使用let时在for循环的每次迭代中都创建了一个新的“i”绑定,那么增加的值是如何传递给i的新绑定的?
如何用 i 的当前值实例化 i 的新绑定?
我们真的在不同的范围内有两个具有不同值的 i 绑定,如果是的话,这些范围是什么?
提前致谢
function a() {
for (let i = 0; i < 3; i++) {
setTimeout(function () { console.log(i) },i * 1000);
}
}
a();
解决方法
如果 JS 在使用 let 时在 for 循环的每次迭代中都创建了一个新的“i”绑定,那么增加的值是如何传递给新的 i 绑定的?
在迭代结束时,值从前一个环境记录复制到下一个。
我们真的在不同的范围内有两个具有不同值的 i 绑定,如果是的话,这些范围是什么?
我想在这里引入术语环境记录,这是规范用来描述绑定值的“事物”的术语。有多个环境记录(每次迭代一个),它们都具有相同的范围(可以在循环体内部访问值),并且可能具有不同的生命周期和值。
您会在ES262,13.7.4.9 Runtime Semantics: CreatePerIterationEnvironment
中找到这一切 ,您在块范围内用 let
声明的任何内容都只能在那里使用。但它将是一个单个实例。在您的示例中,您提供给 console.log()
函数的参数是一个简单值(而不是对象),因此它在 for
循环中调用时“按值”传递。值为 0
、1
和 2
。如果您查看我修改后的类似循环示例,您会注意到在我的情况下,每个 setTimeOut()
调用都将引用同一个对象 o
并且属性 o.i
在执行时,对于所有树调用,它将是 3
(o.i
after 循环结束后的值)。
for (let i,o={i:0}; o.i < 3; o.i++) {
i=o.i;
setTimeout(function () { console.log(i,o.i) },o.i * 1000);
}
为了演示值传递和引用传递之间的区别,我在混合中添加了本地变量i
。此变量由循环中对象属性 for
的最新(在 o.i
循环中)值更新,然后按值传递到console.log() 函数。与此相反,表达式 console.log(i,o.i)
将在稍后执行,当 setTimeOut()
函数触发时。到那时,对象 i
的属性 o
将是 3
。