1

When let is used in the initialiser expression of a traditional for loop, it is scoped to the block of the for loop.

The spec says:

let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment.

Does that mean that the point of declaration of i is (and even in ES5 was(?)) lexically (semantically I know using var it would be hoisted) inside the block comprising the body of the for loop (because naively it looks like it is outside it).

Or does it mean that this is a new feature of let and/or the for loop to give it the semantics of being lexically inside the loop body?

To be clear: I know that the visibility semantics are new (i.e. block scoping for let vs function scooping for var). I am interested in whether the lexical position of definition has always been taken to be inside the body of the loop.

for(let i = 0; i < 10; i++) {
  // the body of the loop....
}
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • "*Does that mean that the point of declaration of `i` is lexically inside the block comprising the body of the for loop?*" - No, what makes you think that? – Bergi Jun 20 '17 at 16:14
  • 1
    Related: [The semantics of `let` and block scoping with for loops](https://stackoverflow.com/q/30899612/1048572) – Bergi Jun 20 '17 at 16:16
  • Shouldn't this post be tagged with [tag:language-lawyer]? – Dragomok Jun 20 '17 at 16:17
  • @Bergi I know this is basic stuff, but I just assumed I understood how it worked. Then I thought about it... Computers are hard – Ben Aston Jun 20 '17 at 16:20
  • @Bergi - intuitively it seemed that the semantic difference for `let` and `var` in a for loop was *more* than just the hoisting aspect. I was grasping at what that additional difference was. I think your linked answer tells me... – Ben Aston Jun 20 '17 at 16:28
  • @Ben I think the designers had the elimination of the [closures-within-for-loop problem](https://stackoverflow.com/q/750486/6445533) in mind, amongst other things. –  Jun 20 '17 at 16:37
  • That prompted the question! – Ben Aston Jun 20 '17 at 16:49

1 Answers1

2

Actually, think of it like an imaginary wrapper block with all the for-declared variables aliased within it. Kind of like this:

// Original
for (let i = 0; i < 10; i++) { ... }

// Equivalent
{
    let _i;
    for (_i = 0; _i < 10; _i++) {
        let i = _i;
        ...
        _i = i;
    }
}

It works by creating a new scope within the for to alias the variables, and then effectively updating the aliases at the end of each block.

(Of course, engines implement it differently than this, but that's when you get into compiler theory and the difference between observable semantics and actual implementation.)

Claudia
  • 1,197
  • 15
  • 30
  • In ES2015 is a `var` declaration in the initialiser expression taken to have a **lexical** point of declaration inside or outside of the for-loop body block? – Ben Aston Jun 20 '17 at 16:06
  • `var` is hoisted to the top of the function as it always has. Nothing has changed in that regard. – Claudia Jun 20 '17 at 16:13
  • the binding-per-iteration feature is not applicable to `const` with traditional for loops. The hoisting behavior of `let`, `const` *is* the same per your answer, however. The binding-per-iteration behavior was the missing piece of my understanding. – Ben Aston Jun 20 '17 at 16:50
  • I've edited my answer accordingly. – Claudia Jun 20 '17 at 17:09
  • This is definitely not right, each iteration of the loop absolutely gets its own `i` binding. – loganfsmyth Jun 20 '17 at 17:24
  • I fixed it. Sorry for the misstep. (I sometimes get that mixed up myself. :-\ ) – Claudia Jun 20 '17 at 17:27
  • I've also CW'd it, so it can be better improved. – Claudia Jun 20 '17 at 17:28