Closure-Based Memoization

Closure-based memoization uses a closure to keep a private cache between function calls. When the same inputs appear again, the cached result can be returned instead of recomputing it.

A closure is a function that retains access to variables from its surrounding lexical scope even after that surrounding function has returned. This makes it useful for storing state that should persist across calls without exposing the state directly.

For memoization, the retained state is typically a cache such as a `Map`. The wrapper checks whether an input has already been computed; if so, it returns the stored value. Otherwise, it calculates the result, stores it, and returns it.

The technique is especially useful for deterministic or otherwise repeatable computations where identical inputs produce identical outputs. The cache key must correctly represent the function's relevant inputs; otherwise, the program can return an incorrect cached value.

Because the cache is private to the returned closure, callers normally cannot modify it directly. The tradeoff is that cached entries consume memory for as long as the closure remains reachable, so an unbounded cache can become a resource problem.

Key points

Interview questions

What is closure-based memoization, and why does the closure matter?

Memoization stores a function's previous results so repeated inputs can avoid repeated computation. A closure lets the returned function retain access to a cache created in its outer function. Because that cache is captured by the closure, it persists between calls without needing global state. This also gives the cache useful encapsulation.

How would you implement a memoization helper in JavaScript?

I would create a `Map` inside a function and return a wrapper that closes over that map. The wrapper checks for a cached input before invoking the original function. On a miss, it computes the value, stores it, and returns it. For multiple arguments, I would also define a reliable strategy for constructing cache keys.

What kinds of functions are good candidates for memoization?

Memoization works best when a function is deterministic for the inputs being cached and the computation is expensive enough to justify storing results. Pure functions are particularly straightforward because repeated inputs have the same output and no required side effects are lost. Functions whose results depend on changing external state need additional care because an old cache entry may become invalid.

What are the time and space tradeoffs of memoization?

A cache hit can reduce the repeated computation to roughly the cost of a cache lookup, depending on the key and data structure. The tradeoff is additional memory proportional to the number and size of cached entries. Cache management can also add overhead on misses because the program must perform lookups and store results. For long-lived closures, an unbounded cache can become a memory-management concern.