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.
Use const if you want the identifier within the loop body to be read-only (so that, for instance, if someone modifies the code later to add an assignment, it's a proactive error).
for/in and for/of expose the same behavior for const and let , but the normal for loop does not. It explicitly treats const differently (understandably maybe). You simply say that it is "declared once" but that simplifies it too much IMO.
In JavaScript, `const` means that the identifier can't be reassigned. (Not to be confused with immutable values. Unlike true immutable datatypes such as those produced by Immutable. js and Mori, a `const` object can have properties mutated.)
As we knew that 'let & const' are not coming in ES5, those are coming in ES6 since 2015. So to make these work like in latest version ECMA Scripts 2015, we can define it by ourself. actually 'let' in ES6 has function to make scope in 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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With