Output Quiz #2 — Closures & the Loop Problem

10 output questions on the classic var loop, let loop, IIFE fix, stale closures, and counter factories — the closure patterns every interviewer tests.

10 min read
JavaScript
Interview
Output

TABLE OF CONTENTS
Output Quiz #2 — Closures & the Loop Problem

Closures are the most tested topic in JS interviews — and the output questions around them are deceptively simple until you understand exactly when a variable's value is captured. Ten questions covering the classic loop problem, stale references, and private state.


Q1 — The classic var loop

Loading editor...

Show answer

Output:

3
3
3

Why: All three setTimeout callbacks close over the same i variable — there is only one i because var is function-scoped. By the time the callbacks run (after the loop finishes), i is 3. Each callback logs the current value of i, which is 3 for all of them.


Q2 — Fix with let

Loading editor...

Show answer

Output:

0
1
2

Why: let in a for loop creates a new binding for each iteration. Each callback closes over its own copy of i — not a shared variable. When the callbacks run, each one reads its own frozen value (0, 1, 2).


Q3 — Fix with IIFE

Loading editor...

Show answer

Output:

0
1
2

Why: The IIFE is called immediately on each iteration, passing the current value of i as j. Each callback closes over its own j parameter (a new variable in each IIFE invocation), not the shared i. This was the standard pre-let workaround.


Q4 — Stale closure reference

Loading editor...

Show answer

Output:

2
3

Why: Both increment and getCount close over the same count variable in the outer makeCounter scope — they share live access to it, not a snapshot. snap is just another reference to the same getCount function. Calling snap() after a third increment() still reads the current value of count, which is now 3.


Q5 — Closure over a reassigned variable

Loading editor...

Show answer

Output:

updated

Why: read closes over the variable value itself, not the string "original". When value is reassigned to "updated" before read() is called, the closure sees the new value. Closures capture variables, not values — this is the root cause of the classic loop problem too.


Q6 — Each call gets its own scope

Loading editor...

Show answer

Output:

8
13
false

Why: Each call to makeAdder creates a brand new execution context with its own x binding. add5 closes over x = 5; add10 closes over x = 10. They are entirely independent function objects — add5 === add10 is false.


Q7 — Closure in an object method

Loading editor...

Show answer

Output:

42
84

Why: Both reveal and double are closures over the same secret variable. double mutates it; reveal reads it. Since they share the same lexical scope, changes made by double are immediately visible to reveal. secret is private — it can't be accessed directly from outside createObj.


Q8 — Loop with array push

Loading editor...

Show answer

Output:

3
3
3

Why: Same root cause as Q1 — all three arrow functions close over the single var i. The loop runs to completion (i becomes 3) before any function is called. All three calls return 3. Change var to let and you get 0, 1, 2.


Q9 — Closure lifespan

Loading editor...

Show answer

Output:

11
12
11

Why: Each call to outer() creates an independent closure environment with its own x. fn1 and fn2 do not share x. fn1() called twice increments its own x from 10 to 11, then 12. fn2() starts its own x fresh at 10, increments to 11.


Q10 — Immediately-returned closure

Loading editor...

Show answer

Output:

1
2
3

Why: The IIFE runs once, creating a count variable and returning the inner function. result holds that inner function. Each call to result() increments and returns count. Because the IIFE has already run, there's no way to reset count from outside — it's private state managed by the closure. This is the module pattern.


Key Rules

PatternWhat the closure captures
var in a loopOne shared variable — all callbacks see the final value
let in a loopA new binding per iteration — each callback sees its own value
IIFE workaroundParameter of the IIFE is a new variable — same effect as let
Closure over outer varThe variable itself, not a snapshot — reassignment is visible
Multiple closures, same scopeAll share the same live variable
Multiple calls to outer fnEach call creates an independent scope

Go Deeper


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI