Output: Closures

⭐ Interview Importance: HIGH
⏱️ Revision Time: 4 min

TL;DR

Closure output questions test whether you understand how inner functions hold onto memory references, especially inside loops or asynchronous callbacks.

Question 1: The Classic var Loop

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 100);
}

Output:

3
3
3

Why?
The var keyword is function-scoped (or globally scoped here). It ignores the for loop block. There is only ONE variable i in memory. The setTimeout pushes 3 callbacks into the Macrotask queue. 100ms later, the loop has completely finished, and i has been incremented to 3 (which broke the loop condition). All three callbacks look up the scope chain, find the single i variable, and print 3.
(Fix: Change var to let to create block-scoping, where each iteration gets a separate i in memory).


Question 2: Closure State Mutation

function createCounter() {
  let count = 0;
  return function() {
    console.log(count++);
  };
}

const counter1 = createCounter();
const counter2 = createCounter();

counter1();
counter1();
counter2();

Output:

0
1
0

Why?
Every time you invoke the outer function createCounter(), JavaScript creates a brand new, separate execution context and a separate closure memory space.
counter1 and counter2 do NOT share the same count variable. They point to two completely independent backpacks of memory. counter1 increments its own private count to 1, while counter2 accesses its own fresh count starting at 0.


Question 3: The Double Return

function sum(a) {
  return function(b) {
    if (b === undefined) return a;
    return sum(a + b);
  };
}

console.log(sum(1)(2)(3)());
console.log(sum(5)(10)());

Output:

6
15

Why?
This is a recursive currying function using closures.

  • sum(1) returns a function holding a=1 in closure.
  • (2) executes that returned function. b is 2. It calls sum(1+2), which returns a new function holding a=3 in closure.
  • (3) executes that function. b is 3. It calls sum(3+3), returning a function holding a=6.
  • () executes that function without arguments. b is undefined. The if statement triggers, returning the closure variable a, which is 6.