首页 > 解决方案 > ES6中for循环的作用范围是什么?

问题描述

letJavaScript for 循环中的操作范围到底是什么?

for (let i = 0; i < 3; i++) {
  let i = 4;
  console.log(i);
}
console.log(i);

外部console.log抛出错误:

“未捕获的引用错误:我未定义”

它证明i是在块操作范围内,但是,为什么ifor循环中的定义不抛出任何重复定义错误?

标签: javascriptfor-loop

解决方案


循环体for(带有let变量声明)有两个作用域(或 LexicalEnvironments):一个作用域是迭代环境,它包含letfor循环声明中声明的变量,内部作用域包含在 for 循环体中声明的变量(之后{)。这在规范中进行了描述,从13.7.4.7 Runtime Semantics: LabelledEvaluation开始

IterationStatement : for (LexicalDeclaration Expression; Expression) 语句

(这就是for用 is 声明变量的循环let。)

评估上述内容最终会让您:

  1. 让 bodyResult 为 ForBodyEvaluation(第一个 Expression,第二个 Expression,Statement,perIterationLets,labelSet)。

请注意,“语句”可以是一个(可以以 开头{和结尾},就像大多数for循环体一样)——这非常重要,因为一个块创建了另一个词法环境。

13.7.4.8 运行时语义:ForBodyEvaluation说:

  1. 履行 ?CreatePerIterationEnvironment(perIterationBindings)。

  2. 重复,

    湾。让 result 是评估 stmt 的结果。

    ...

    e. 履行 ?CreatePerIterationEnvironment(perIterationBindings)。

whereCreatePerIterationEnvironment 创建一个包含letfor循环声明中声明的变量的环境:

    G。对于 perIterationBindings 的每个元素 bn,执行

        一世。履行 !thisIterationEnvRec.CreateMutableBinding(bn, false)。

        ii. 让 lastValue 成为 ? lastIterationEnvRec.GetBindingValue(bn, true)。

        iii. 执行 thisIterationEnvRec.InitializeBinding(bn, lastValue)。

因此,有两种作用域:一种由 . 创建的CreatePerIterationEnvironment,另一种由 is 的块创建stmt

for (let i = 0; i < 3; i++) {
  let foo = 'f';
}

这里,i包含在外部迭代环境中,foo包含在内部块中,这是一个不同的环境。如果您使这两个变量名称相同,则不会引发错误,因为let <variableName>在块内部会创建一个范围为该块的变量,并且不会尝试在迭代环境中覆盖具有相同名称的变量。


推荐阅读