Avoid repeated computation
An expensive pure calculation receives the same input repeatedly.
JS Puzzles · Const
Memoization caches a function's result for an input so repeated calls can avoid recalculation. In JavaScript, it is commonly implemented as a decorator backed by a Map.
Memoization wraps a frequently called function and stores each computed result in a Map. Later calls with the same argument read the cached value instead of recalculating it; call/apply-style forwarding can preserve the original receiver and arguments when the wrapper delegates execution.
function cachingDecorator(func) { /* return a caching wrapper */ }| Name | Type | Description |
|---|---|---|
func | Function | The function whose results should be cached. |
context | any | The execution context forwarded to the wrapped function. |
args | array-like | Arguments forwarded to the wrapped function. |
A wrapper function that caches results for repeated inputs.
function memoize(fn) {
const cache = new Map();
return function (x) {
if (cache.has(x)) return cache.get(x);
const result = fn.call(this, x);
cache.set(x, result);
return result;
};
}
const slowSquare = memoize((x) => x * x);
console.log(slowSquare(5));
console.log(slowSquare(5));The wrapper computes a result once for each argument and returns the cached value on later calls.
An expensive pure calculation receives the same input repeatedly.
A recursive algorithm reaches identical subproblems.
A frequently called function needs behavior added without changing its body.
A memoization decorator keeps a Map from an argument to the result. On each call it checks the Map, returns a stored value on a hit, and otherwise calls the original function, stores the result, and returns it.
Follow-up: How would you support several arguments? Use a stable compound key or nested Maps, and ensure the key distinguishes every input combination.
The wrapper must forward the call to the original function. func.call(context, ...) supplies an explicit this, while func.apply(context, args) supplies the context plus an array-like argument list.
Follow-up: What can break when forwarding? A wrapper that invokes the function without preserving this can change behavior for methods that read instance state.
Memoization trades additional storage for fewer repeated calculations. It is most useful when calls recur with the same inputs and the wrapped function's result can safely be reused.
Follow-up: What policy may be needed for an unbounded cache? Add eviction or an explicit lifetime so retained entries do not grow indefinitely.
Mapcallapplydecoratorcall forwarding