What does this JavaScript code log to the console? for (var i = 0; i < 3; i++) { setTimeout(() => {…
What does this JavaScript code log to the console? for (var i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); } Most developers expect: 0 1 2 What actually prints after 1 second: 3 3 3 Why does JavaScript skip 0, 1, and 2 completely? Here is what happens under the hood when Asynchronous Timers collide with Closures: 1. The Single Memory Slot of "var" "var" is function-scoped, not block-scoped. The JavaScript engine does NOT create a new variable for each loop round. Instead, it allocates a single memory slot in the parent scope and mutates it on every step: i = 0 ➔ i = 1 ➔ i = 2 ➔ i = 3 (loop terminates). 2. The Event Loop Delay The "for" loop runs synchronously and finishes in fractions of a millisecond. Meanwhile, the setTimeout callbacks are sent to the Web API timer pool and then queued in the Task Queue. By the time the Call Stack clears and those callbacks finally fire (after 1000ms), the loop has already completed. The shared "i" variable in memory is now sitting at 3. All 3 callback functions hold a closure reference to the EXACT SAME variable slot. Result: 3, 3, 3. 3. The ES6 Fix: Block-Scoped "let" Simply swap "var" for "let": for (let i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); } Output: 0, 1, 2 Why does this work? The JavaScript specification treats "let" in a for-loop header specially: The engine creates a brand-new lexical environment (a fresh memory binding) for EVERY single iteration. Each callback closes over its own independent snapshot of "i". 4. The Pre-ES6 Solution: IIFEs Before "let" arrived in 2015, engineers had to manually create a new scope per loop cycle using an IIFE: for (var i = 0; i < 3; i++) { (function(index) { setTimeout(() => { console.log(index); }, 1000); })(i); } Understanding how closures capture references instead of static copies is what separates guessing output from truly understanding the runtime. Did you first encounter this trap in an interview or inside production code?