easyJS ES5#51

Closure counter factory

Prompt

Write a function createCounter that returns an object with increment and getValue methods. The count variable must be private — enforced via closure, not convention. Two counters created separately must not share state.

Solution

function createCounter() {
  var count = 0
  return {
    increment: function() { count++ },
    getValue: function() { return count },
  }
}
Mentor's take

Pre-#private fields, closures were JavaScript's only real access modifier — and this factory is the canonical proof you understand why they work, not just that they do. Each call to createCounter creates a new execution context with its own lexical environment containing count. Normally that environment dies when the call returns; here the two returned functions hold a reference to it, so the GC keeps it alive for exactly as long as the counter object lives. That's the entire mechanism of closures: a function plus the environment it was created in.

Two properties fall out for free. True privacycount is not a property on the returned object, so no consumer can read or corrupt it; the closure is the only door. Instance isolation — every factory call builds a fresh environment, so counters never share state.

The trade-off a senior names: each instance carries its own copies of increment and getValue, unlike prototype methods which are shared. For a handful of counters that's irrelevant; for ten thousand instances the prototype pattern wins on memory — privacy versus footprint is the actual choice here.

Red flag: storing the count as this.count and calling it "private by convention." The interviewer asked for closure-enforced privacy; a property is public, period.

Say it: "The returned functions keep the factory's lexical environment reachable, so count lives on, invisible and per-instance — that's closure-based encapsulation, traded against the shared-memory advantage of prototype methods."