ReviseAlgo Logo

Scope & Closures

Practical Closure Patterns

Master practical JavaScript closure patterns. Implement the module pattern, memoization caches, and private state handlers.

Last Updated: July 15, 2026 12 min read

1. Introduction

Closures are more than just a theoretical concept. They are a practical tool used to implement several design patterns in JavaScript, such as the Module Pattern, Memoization Caches, and Private State.

2. Why It Matters

Using closure design patterns lets you hide implementation details, cache expensive calculations, and write self-contained modules, helping you build clean and performant applications.

3. Real-World Analogy

Think of a Smart Office Desk:

  • Module Pattern (Locked Filing Cabinet): A cabinet with a locked drawer for files (private state) and a top tray for forms (public API). You interact with the tray, while the cabinet hides the files.
  • Memoization (Frequently Asked Questions Sheet): A sheet where the receptionist writes down answers to common questions. If a question is asked again, the receptionist reads the answer from the sheet instead of calling a technician to recalculate it.

4. Core Closure Patterns

Let's explore the three primary patterns:

1. The Module Pattern:

Uses closures to create public APIs while hiding internal implementation details, simulating classes with private properties.

2. Memoization (Caching):

Wraps a function with a cache object inside a closure. If the function is called with the same arguments again, the cached result is returned instead of re-running the calculation.

5. Practical Example

Here is a complete, working implementation of a memoized Fibonacci calculator:

6. Common Mistakes

  • Unbounded cache size: In memoization, the cache grows indefinitely as the function is called with new arguments. This can lead to memory exhaustion in production. Implement a size limit or clean up strategies (like LRU caching).

7. Quick Quiz

Q1: Which closure pattern is used to simulate private methods and properties in JavaScript?

A) Iterator Pattern

B) Module Pattern

Answer: B — The Module Pattern uses IIFEs and closures to provide private scopes with public API access.

8. Scenario-Based Challenge

The LRU Memoizer:

Modify the standard memoize pattern to enforce a maximum cache size of 100 entries. If the limit is exceeded, delete the oldest cached item before adding the new result. Outline the storage design.

9. Debugging Exercise

Identify why this memoizer fails when arguments are objects:

function badMemoize(fn) {
  const cache = new Map();
  return function(arg) {
    if (cache.has(arg)) {
      return cache.get(arg);
    }
    const result = fn(arg);
    cache.set(arg, result);
    return result;
  };
}
const check = badMemoize(x => x.id);
check({ id: 1 }); // runs calculation
check({ id: 1 }); // runs calculation again! Why?
View Solution

Diagnosis: A Map key comparison uses SameValueZero comparison rules. When objects are passed as keys, identical objects are treated as different keys because their memory references are different.

Fix: Stringify the arguments to construct a unique, value-based string key:

function goodMemoize(fn) {
  const cache = new Map();
  return function(arg) {
    const key = JSON.stringify(arg);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn(arg);
    cache.set(key, result);
    return result;
  };
}

10. Interview Questions

🟢 Q1: Explain how closures enable the Module Pattern in JavaScript.

Answer: The Module Pattern uses an IIFE to define local variables and helper functions. The IIFE returns an object containing methods that reference those local variables. Because these methods are declared inside the IIFE scope, they form a closure over it, maintaining access to the private variables even after the IIFE has finished executing. The returned object acts as the public API, while the internal variables remain hidden.

11. Production Considerations

  • Cache Eviction: Always implement cache eviction policies (like Least Recently Used - LRU) for memoization caches in long-running applications (like Node.js servers) to prevent memory leaks.