What\'s exactly the action scope of let
in a for-loop in JavaScript?
The body of a for
loop (with a let
variable declaration) has two scopes (or LexicalEnvironments): one scope is the iteration environment, which contains the variables declared with let
in the for
loop declaration, and the inner scope contains variables declared inside the for loop body (after the {
). This is described in the specification, starting at 13.7.4.7 Runtime Semantics: LabelledEvaluation
IterationStatement : for ( LexicalDeclaration Expression; Expression ) Statement
(this is what a for
loop which declares a variable with let
is.)
Evaluating the above eventually gets you to:
- Let bodyResult be ForBodyEvaluation(the first Expression, the second Expression, Statement, perIterationLets, labelSet).
Note that "Statement" can be a block (can start with {
and end with }
, as most for
loop bodies do) - this is very important, because a block creates another lexical environment.
13.7.4.8 Runtime Semantics: ForBodyEvaluation says:
Perform ? CreatePerIterationEnvironment(perIterationBindings).
Repeat,
b. Let result be the result of evaluating stmt.
...
e. Perform ? CreatePerIterationEnvironment(perIterationBindings).
where CreatePerIterationEnvironment
creates an environment containing the variables declared with let
in the for
loop declaration:
g. For each element bn of perIterationBindings, do
i. Perform ! thisIterationEnvRec.CreateMutableBinding(bn, false).
ii. Let lastValue be ? lastIterationEnvRec.GetBindingValue(bn, true).
iii. Perform thisIterationEnvRec.InitializeBinding(bn, lastValue).
So, there are two scopes: one created by CreatePerIterationEnvironment
, and one created by the block that the stmt
is.
for (let i = 0; i < 3; i++) {
let foo = 'f';
}
Here, i
is contained in the outer iteration environment, and foo
is contained in the inner block, which is a different environment. If you made those two variable names names the same, no error is thrown because let
inside the block creates a variable scoped to that block, and does not try to overwrite the variable with the same name in the iteration environment.