> I can understand the intention behind the design, but I feel that, in order to make a common usecase less surprising, they made the whole thing actually more surprising.
I don't agree with that, `for let` simply behaves as if the `let` was inside the loop:
for (var _i=0; _i<3; _i++) {
let i = _i;
setInterval(() => {console.log(i); i+=100}, 1000);
}
I agree with xg15 that it’s surprising, however well-intentioned. The general wisdom is that C-style for loops are simple sugar for while loops, that the following two are equivalent:
for (initialiser; condition; incrementer) { body; }
initialiser;
while (condition) {
body;
incrementer;
}
This made perfect sense and was easy to reason about. Add lexical scoping, and it should obviously have just gained an extra level of scope, so that bindings are limited to the loop:
{
initialiser;
while (condition) {
body;
incrementer;
}
}
But instead, the initialiser became awkwardly half inside the loop and half outside the loop: inside as regards lexical bindings, but outside as regards execution (… and lexical bindings in the remainder of the initialiser). That’s wacky. I understand why they did it, and in practice it was probably the right decision, but it’s logically pretty crazy, and much more convoluted for the spec and implementation. https://262.ecma-international.org/6.0/#sec-for-statement-ru... (warning: 4MB of slow HTML) and the following headings show how complicated it makes it. In essence, you end up with this:
{
initialiser;
{
Lexically rebind every name declared in the initialiser.
(Roughly `let i = i;`, if only that shadowed a parent, as it does
in many such languages, rather than raising a ReferenceError.)
while (condition) {
body;
incrementer;
}
}
}
This reveals also problems in your attempted desugaring:
for (var _i=0; _i<3; _i++) {
let i = _i;
setInterval(() => {console.log(i); i+=100}, 1000);
}
The trouble is that the condition and incrementer are not referring to a var, but rather to your lexical declaration that you put on the next line.
I don't agree with that, `for let` simply behaves as if the `let` was inside the loop:
there you go, same behaviour as a for-let.