So I noticed that I have to use let
inside a for
loop, and cannot use const
. However, I found that I can use const
inside the for-in
and for-of
constructs (code below). Intuitively I can rationalize that this is because the for
loop is implemented differently/is more primitive, whereas the other constructs desugar into for loops where the iterating variable is assigned at the top of the for loop.
// Doesn't work
for (const i = 0; i < 3; i++) {
console.log(i);
}
// Works
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Works
const object2 = ['a', 'b', 'c'];
for (const v of object2) {
console.log(v);
}
// Works
const object3 = {
a: 'a',
b: 'b',
c: 'c',
};
for (const v in object3) {
console.log(v);
}
The only thing I could find on Mozilla MDN about this was on the for loop page:
This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
Which also seems wrong, because if we use a let
for i
then i
is no longer in scope after the for
loop (which is consistent with other languages)
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Doesn't work as expected
console.log(i);
My question is whether this behaviour is expected and defined in the spec somewhere? MDN doesn't say much about this.
So I noticed that I have to use let inside a for loop, and cannot use const.
No. You can use a const
declaration in a for
loop just fine. The problem just is that const
declares a constant binding, so an increment i++
doesn't work on const i
(it should throw an exception, make sure you're in strict mode).
An example of how to use const
:
for (const o = {index: 0, value: null}; o.index < arr.length; o.index++) {
o.value = arr[o.index];
doSomething(o);
}
Or one where it makes more sense:
for (const iterator = makeIterator(); !iterator.isDone(); iterator.next())
doSomething(iterator.getCurrent());
}
Intuitively I can rationalize that this is because the for loop is implemented differently/is more primitive, whereas the other constructs desugar into for loops where the iterating variable is assigned at the top of the for loop.
Yes. In a for
loop, you need to take care of updating the iteration variables yourself.
for ([var] init; condition; update) { body }becomes
[var] init; while (condition) { body; update; }
for (const init; condition; update) { body }
becomes
{ const init; while (condition) { body; update; } }
for (let init; condition; update) { body }
becomes something more complicated
In for … in
and for … of
loops, you just declare an assignment target expression for the produced value.
for ([var]/let/const target of iterable) { body }
becomes
{ const _iterator = iterable[Symbol.iterator](); let _result; while (!(_result = _iterator.next()).done) { [var]/let/const target = _result.value; body; } }
for (… in enumerable)
is just the same as for (… of Reflect.enumerate(enumerable))
.
The only thing I could find on Mozilla MDN about this was on the
for
loop page, which also seems wrong.
Yes, looks like that section hasn't yet been updated for ES6.