ECMAScript 2015: const in for loops

JavascriptFor LoopScopeConstantsEcmascript 6

Javascript Problem Overview


Which of the two (or neither/ both) code fragments below should be working in a complete ECMAScript 2015 implementation:

for (const e of a)

for (const i = 0; i < a.length; i += 1)

From my understanding, the first example should work because e is initialized for each iteration. Shouldn't this also be the case for i in the second version?

I'm confused because existing implementations (Babel, IE, Firefox, Chrome, ESLint) do not seem to be consistent and have a complete implementation of const, with various behaviours of the two loop variants; I'm also not able to find a concrete point in the standard, so that would be much appreciated.

Javascript Solutions


Solution 1 - Javascript

The following for-of loop works:

for (const e of a)

The ES6 specification describes this as:

> ForDeclaration : LetOrConst ForBinding

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-in-and-for-of-statements-static-semantics-boundnames

The imperative for loop will not work:

for (const i = 0; i < a.length; i += 1)

This is because the declaration is only evaluated once before the loop body is executed.

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-statement-runtime-semantics-labelledevaluation

Solution 2 - Javascript

I won't cite the spec this time, because I think it's easier to understand what happens by example.

> for (const e of a) …

Is basically equivalent to

{
    const __it = a[Symbol.iterator]();
    let __res;
    while ((__res = __it.next()) && !__res.done) {
        const e = __res.value;
        …
    }
}

For simplicity I've ignored that there's a TDZ with e for the a expression, and the various __it.return()/__it.throw(e) calls in the case the loop exits prematurely (break or throw in the body).

> for (const i = 0; i < a.length; i += 1) …

is basically equivalent to

{
    const i = 0;
    while (i < a.length) {
        …
        i += 1;
    }
}

In contrast to let, a const declaration in a for loop does not get redeclared in every loop iteration (and the initialiser is not re-executed anyway). Unless you break in the first iteration, your i += will throw here.

Solution 3 - Javascript

Your second example should definitely not work because i is declared once and not on each iteration this is just a function of how that category of loops work.

You can try this in a regular browser:

for (var i = 0, otherVar = ""; i < [1,2,3,4].length; i += 1){
  console.log(otherVar)
  otherVar = "If otherVar was initialized on each iteration, then you would never read me.";
}

It's not the case that const is entirely disallowed in for loops. Only for that will modify const is.

These are valid:

for(const i = 0;;){ break } 
for(const i = 0; i < 10;){ break; } 

These are invalid:

for(const i = 0;;){ ++i; break; } 
for(const i = 0;;++i){ if(i > 0) break; }

I'm not sure why Firefox gives a SyntaxError after reading the ES2015 spec (although I'm sure the clever folk at Mozilla are correct), it seems like it's supposed to raise an exception:

> Create a new but uninitialized immutable binding in an Environment Record. The String value N is the text of the bound name. If S is true then attempts to access the value of the binding before it is initialized or set it after it has been initialized will always throw an exception, regardless of the strict mode setting of operations that reference that binding. S is an optional parameter that defaults to false.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionadrianpView Question on Stackoverflow
Solution 1 - JavascriptlyschoeningView Answer on Stackoverflow
Solution 2 - JavascriptBergiView Answer on Stackoverflow
Solution 3 - JavascriptKit SundeView Answer on Stackoverflow