JS Quiz: Hard: Lexical Scope and Closure Chain

What will be logged to the console when the script runs?

function createCounter(initialValue) {
  let count = initialValue;

  function increment() {
    count++;
    return count;
  }

  function decrement() {
    count--;
    return count;
  }

  return { increment, decrement };
}

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

counter1.increment();
counter2.decrement();
counter1.increment();

console.log(counter1.increment());
console.log(counter2.decrement());
  • 7\n9
  • 7\n8
  • 6\n9
  • 6\n8
0 voters

The createCounter function makes separate count variables for counter1 and counter2.

counter1 starts at 5, increments three times, then the console.log increments it to 9. counter2 starts at 10, decrements twice, and the console.log decrements it to 7. So it should be 9 and 7.

JS Quiz answer: Option 2 (B).

Correct choice: 7\n8

Why:
This example demonstrates lexical scope and closures. Each call to createCounter creates a new, independent count variable in its own lexical environment. The increment and decrement functions returned by createCounter close over their respective count variables.

counter1 starts with count = 5.

  1. counter1.increment() makes count = 6.
  2. counter1.increment() makes count = 7.
  3. console.log(counter1.increment()) makes count = 8 and logs 8.

counter2 starts with count = 10.

  1. counter2.decrement() makes count = 9.
  2. console.log(counter2.decrement()) makes count = 8 and logs 8.

Therefore, the output is 8 then 8.

Go deeper:

CSS Variables JavaScript Win

First-answer leaderboard

  1. @Apexcodes - 6 (firsts) :trophy:
  2. @kirupa - 6 (firsts) :trophy:
  3. @emmawalter5 - 3 (firsts)
  4. @adnanahmed - 2 (firsts)

The interesting question here isn’t just how this works, but what the implications are for state management in larger systems. Each counter instance having its own isolated state is a powerful pattern for avoiding unintended side effects.

It’s good for avoiding unintended side effects, but it can also make debugging tricky when you have many layers of closures. Tracing the state becomes a bit like following a musical fugue.

That’s a good way to put it, like a musical fugue. I’ve definitely lost an afternoon trying to untangle a closure chain that got too deep.

Hmm interesting