DEV Community

Discussion on: Const is applicable on For of Loops but not on For Loops (Why)

Collapse
 
peerreynders profile image
peerreynders

The let in the modern for loop is actually a bit disingenuous.

The early version of the for loop worked like this:

for (var i = 0; i < 2; i += 1) {
  queueMicrotask(() => console.log(i));
}
// Output:
// 2
// 2
Enter fullscreen mode Exit fullscreen mode

Unintuitive but correct as by the time console.log() executed i was 2.

Typically the intention is this:

for (var i = 0; i < 2; i += 1) {
  queueMicrotask(makeTask(i));
}
// Output:
// 0
// 1
function makeTask(v) {
  return () => console.log(v);
}
Enter fullscreen mode Exit fullscreen mode

The let version automatically works that way

for (let i = 0; i < 2; i += 1) {
  queueMicrotask(() => console.log(i));
}
// Output:
// 0
// 1
Enter fullscreen mode Exit fullscreen mode

A new lexical scope is created for each iteration and each lexical closure has its own copy of i.

for ([initialization]; [condition]; [final-expression])
  statement
Enter fullscreen mode Exit fullscreen mode
  1. initialization initializes the loop environment‡.
  2. final-expression runs at the beginning of each iteration except the first one.
  3. before condition is checked a new lexical environment is created for the iteration and the current loop environment (i) is copied into that then condition is checked. Continue if satisfied, break if not.
  4. statement is executed.
  5. the lexical environment is copied back to the loop environment.
  6. goto step 2
for (let i = 0; i < 2; i += 1) {
  queueMicrotask(() => console.log(i));
  i += 1;
}
// Output:
// 1
Enter fullscreen mode Exit fullscreen mode

initialization has its own lexical scope.

for (let i = (queueMicrotask(() => console.log(i)), 0); i < 2; i += 1) {
  i += 1;
}
// Output:
// 0
Enter fullscreen mode Exit fullscreen mode

Collapse
 
ibrahim_harchiche profile image
Ibrahim Harchiche • Edited

"final-expression runs at the beginning of each iteration except the first one. "
mdn says: final-expression (called afterthought in their docs) evaluates at the end of each loop iteration not at the beginning of each iteration.