Make Counter: The Classic Closure Question

makeCounter is the canonical closure interview question. Start with a simple increment counter, then build the full version with reset, increment, decrement, and getValue methods.

8 min read
JavaScript
Interview
Implementation
Closures

TABLE OF CONTENTS

makeCounter is the canonical closure interview question. If you understand why the returned function remembers its variables, you understand closures. The question starts simple and escalates — here's how to handle both versions.

Related deep-dive: JS Foundations #3 — Closures & Lexical Scope


What is makeCounter()?

makeCounter() is the simplest possible demonstration of closures — the mechanism by which an inner function retains access to variables from its enclosing scope, even after that scope has finished executing. Understanding this question means understanding closures, period.

When you call makeCounter(), it creates a local variable (typically count) and returns a function. That returned function "closes over" count — meaning it holds a live reference to the variable, not a frozen copy. Each subsequent call mutates the same count, and no outside code can touch it. This is the module pattern in microcosm: private state exposed through a public API.

The interview usually escalates from the simple one-function version to an object with multiple methods (increment, decrement, reset, getValue), all sharing the same closed-over state. The key realization: every call to makeCounter() spawns an independent closure with its own private count. Two counters never interfere.

Closures power virtually every modern JS pattern — event handlers, memoization, currying, debouncing, and the entire React hooks model. If you can explain makeCounter, you can explain all of them.


The Problem

Version I:

"Write a makeCounter function that returns a counter. Each call to the returned function increments and returns the count, starting from 0."

Version II (the interviewer will extend):

"Now modify it so the counter object has four methods: increment(), decrement(), reset(), and getValue()."


Thought Process

A closure is created when a function "remembers" the variables from its outer scope, even after that outer scope has finished executing. For a counter, the outer function makeCounter creates a variable. The inner function closes over it. Each call to makeCounter creates a new, independent closure.

Key insight: the variable is private. Nothing outside the returned function can access or modify it directly. This is the module pattern in its simplest form.


Step 1 — Version I: Simple Closure Counter

Loading editor...

That's it. One variable, one returned function that closes over it. But the interviewer isn't done.


Step 2 — Version II: Counter Object with Methods

The interviewer now says: "Turn it into an object with four methods."

Loading editor...


Step 3 — Why Closures Make This Work

Here's what the interviewer wants you to articulate:

  1. When makeCounter is called, a new execution context is created with a local variable count.
  2. The returned object's methods hold references to count — not a copy, the actual variable.
  3. Even after makeCounter returns and its execution context is popped off the call stack, count is not garbage-collected because the closures still reference it.
  4. Each call to makeCounter creates a new, separate count variable — the closures are independent.

This is the same mechanism that powers the module pattern, memoization, and event handlers in loops.


Step 4 — Edge Cases

Starting from a non-zero value: The initialValue parameter handles this. Default it to 0 so the counter works with no arguments.

Calling reset(): Should return to initialValue, not 0 (unless initialValue was 0). This is a detail interviewers notice — if you reset to 0 instead of the initial value, that's a bug.

What if someone passes a non-number? The native behavior would still work — JavaScript would coerce it. Don't add validation unless asked.

Making count truly unreachable: Since we return an object with methods, those methods can access count. But there's no way to get count directly — only through getValue(). The data is truly private.


Full Solution

Loading editor...


What Interviewers Are Testing

  • Closure fundamentals — you understand that inner functions retain access to outer variables after the outer function returns
  • Lexical scope — you know count is scoped to makeCounter, not the returned function
  • Data privacy — you recognize that closures create truly private state (no way to access count except through the API)
  • Independent instances — you understand that each makeCounter() call creates a fresh closure with its own count

Complexity

OperationTimeSpace
All methodsO(1)O(1)

Interview Tips

  • Say "closure" immediately — when the interviewer asks "how would you implement a counter?", respond "this is a closure — an inner function that captures a variable from its enclosing scope." This shows you recognize the pattern.
  • Write version I in 3 lines — don't over-explain the simple version. Save your energy for version II, where the discussion happens.
  • Use ++count not count++ — pre-increment returns the updated value directly, so you can write return ++count instead of count++; return count;. It's a small thing that shows fluency.
  • Mention garbage collection — when asked "how does the variable stay alive?", explain that the closure reference prevents GC. This signals deeper knowledge.

Related Questions


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI