我知道let具有块级作用域,而var具有函数级作用域。但是在这种情况下,我不明白如何使用let可以解决问题。
const arr = [1,2,3,4];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log(arr[i])
}, 1000);
} // Prints undefined 5 times
const arr = [1,2,3,4];
for (let i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log(arr[i])
}, 1000);
} // Prints all the values correctly
let
变量是在for
循环内部作用域还是外部?有四个不同的i
吗,还是只有一个?如果只有一个,那么它与var
情况有何区别(假定只有一个i
也会被闭包捕捉,就像var
一样)?如果有四个,为什么i++
有效(即如何访问旧的i
和新的i
)?如果有ES2018相关段落,那就太棒了。(编辑:提议的重复问题已经有答案了。) - AmadanIn the second case, i is not hoisted, and has scoped access to each iteration of the loop, making i accurately available to console.log statement.
That is right but the execution of loop won't stop forsetTimeout
.In this case also the loop will finish and if you log the value ofi
outside settimeout, you will see it's valuei
is set tolength-1
much before thesettimeout
have started execution. So the question is howsettimeout
get the value ofi
even when its value is setlength-1
- brki++
在哪个范围内,获取澄清它的规范段落的参考将会很棒。如果i++
在作用域内,那么它应该在每次迭代中使用相同的变量,因为++
修改了一个现有的变量;如果i++
在作用域外,则应该未知i
;但这两者都不是实际发生的情况。从babel编译的版本来看,我可以看到发生了什么(外部作用域的i
传递为值到内部作用域的i
),但我不知道如何在规范中解释它。 - Amadani
在块内部,每次迭代都会创建一个新的词法环境。根据ECMA2017版第13.7.4.7节中的“IterationStatement : for ( LexicalDeclaration Expression ; Expression ) _Statement_”,第2步创建了一个循环环境,并在第7步设置了该环境。根据第13.7.4.8节,循环环境在第一次循环迭代之前(第2步)被复制,并在循环结束之前以其现有状态再次复制,然后进行`++i'增量(第3.e步)。循环终止后恢复先前的环境。 - traktor