All topics
Performanceintermediate

Memoization and Caching Strategies

Storing the results of expensive function calls keyed by their arguments, so repeated calls with the same input can return a cached result instantly.

Memoization is an optimization technique that caches the result of an expensive function call keyed by its input arguments, so subsequent calls with the exact same arguments can return the cached result immediately instead of redoing the same expensive computation — a specific, targeted application of the broader idea of trading memory for time, valuable specifically when a function is pure (same input always produces the same output) and is called repeatedly with a meaningfully repeating set of inputs.

Memoization is like a chef who, instead of re-cooking an entire dish from scratch every single time a specific order comes in, keeps a small stash of a few recently prepared dishes on standby — if the exact same order comes in again while that stash entry is still fresh, it goes straight out from the stash instead of back through the whole cooking process again.

Key Concepts

1
A basic memoization wrapper is a higher-order function: it takes the original function and returns a new function that, on each call, first serializes or otherwise derives a cache key from the arguments, checks whether that key already exists in an internal cache (commonly a Map, since it handles arbitrary key types more gracefully than a plain object), and either returns the cached value immediately or computes the real result, stores it in the cache under that key, and then returns it — every subsequent call with the same arguments hits the cache instead of recomputing.
Map
2
The classic illustrative example is naive recursive Fibonacci, which recomputes the same overlapping subproblems exponentially many times without memoization; adding a cache keyed by the input n turns an otherwise exponential-time computation into a linear-time one, since each unique subproblem only ever needs to be actually computed once no matter how many times it's referenced elsewhere in the recursion tree.
n
3
Memoization isn't free, though, and has real tradeoffs worth being explicit about in an interview: the cache itself consumes memory, potentially unboundedly if there's no eviction strategy for old entries (a genuine memory-leak risk for long-running processes memoizing calls with many distinct argument combinations over time); deriving a reliable cache key for complex object arguments (rather than simple primitives) can be non-trivial, since naive JSON.stringify-based keys can be slow for large objects and don't handle things like functions or circular references at all; and memoization is fundamentally inappropriate for impure functions whose output depends on anything besides their literal arguments, since the cache would then return stale, incorrect results for inputs whose 'true' answer has since changed. Libraries and frameworks (like React's useMemo/memo, or Lodash's _.memoize) implement more refined versions of this same core idea, often adding cache-size limits or other eviction strategies on top of the basic technique.
JSON.stringifyuseMemomemo_.memoize