ECMAScript 2015: const in for loops

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.


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


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.