Browse documentation

Opt-in traditional for loops

Date: 2026-05-05 Area: parser

Opt-in traditional for(init; test; update) loops (--compat-traditional-for-loop). Added behind a new compatibility flag for ECMAScript compatibility when porting legacy code, mirroring the existing --compat-var and --compat-function pattern. The flag is off by default and ORed in by --compat-all so test262 (which always passes --compat-all) executes traditional for(;;) bodies that previously parser-warn-and-skipped — surfacing real engine gaps in unrelated areas (Atomics #541, Intl #542, BigInt postfix increment #540, etc.). let/const declarations in for-init create a per-iteration lexical environment per ES2026 §14.7.4.4, so closures captured during iteration N pin to that iteration's binding (the textbook fns.push(() => i) case yields [0, 1, 2], not [3, 3, 3]). var declarations require both --compat-var and the new flag and share a single hoisted binding visible after the loop. The bytecode compiler reuses the counted-loop pattern from CompileCountedForOf for for(let i = N; i <op> M; i++ | i--) shapes (rejecting var/const, bodies that mutate the loop var, type annotations, and non-integer-literal cond RHS). while and do...while remain excluded — they have the same stub status but were intentionally split into a separate iteration. language-tables.md.