JavaScript Memoization
Written By: Avinash Malhotra
Updated on
Memoization is an optimization technique that stores a function's result for a given input and reuses it when the same input appears again. This JavaScript tutorial shows how to build a memoized function, optimize recursive calculations, and avoid common caching mistakes.
- Use memoization when a function is expensive and receives repeatable inputs.
- Keep the cache private to the function and choose a key that represents every input.
- Remember that faster lookups use memory, so memoization is not useful for every function.
What is Memoization in JavaScript?
Memoization is a programming technique where a function caches its results based on its input parameters. When the function is called with the same parameters again, it returns the cached result instead of recalculating it.
This technique is particularly useful for functions that are called repeatedly with the same arguments, as it can significantly improve performance by avoiding redundant calculations.
Simple idea: cache results to avoid repeated work.
Memoization Example
Here is a simple example using a cache object to store square values. If a value is already cached, JavaScript returns it without performing the calculation again.
const cache = {};
function square(n) {
if (cache[n] !== undefined) {
console.log("From cache");
return cache[n];
}
console.log("Calculating...");
cache[n] = n * n;
return cache[n];
}
console.log(square(5)); // Calculating... → 25
console.log(square(5)); // From cache → 25
console.log(square(10)); // Calculating... → 100
console.log(square(10)); // From cache → 100
This approach ensures that the function is only called once for each unique input, significantly improving performance for expensive operations.
Create memoized function
A reusable memoize helper function can cache the result of any function. This is most effective for pure functions: functions whose output depends only on their inputs and that do not cause side effects.
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (key in cache) {
return cache[key];
}
const result = fn.apply(this, args);
cache[key] = result;
return result;
};
}
const factorial = memoize(function(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
});
In this example, the memoize function wraps the factorial function, caching its results to avoid redundant calculations.
Memoizing an Array Calculation
Memoization can also help when an array calculation is repeated with the same data. For a one-time sum, however, JavaScript's reduce() method is simpler and caching usually adds unnecessary memory use.
const cache = {};
function sumArray(arr) {
const key = JSON.stringify(arr);
if (cache[key] !== undefined) {
console.log("From cache");
return cache[key];
}
console.log("Calculating...");
const result = arr.reduce((sum, num) => sum + num, 0);
cache[key] = result;
return result;
}
Real-World Uses of Memoization
Memoization is useful when an application repeatedly requests the same calculation and the inputs can be represented by a stable cache key.
- Dynamic programming: Store solutions to overlapping subproblems, such as Fibonacci calculations.
- UI calculations: Reuse derived values when the same state or inputs are rendered repeatedly.
- Parsing and formatting: Cache expensive transformations when the source value does not change.
- API request deduplication: Reuse an existing result when the same request parameters are repeated, with an appropriate expiration policy.
When Not to Use Memoization
Memoization is not automatically faster. Avoid it when a function is cheap, its inputs rarely repeat, its result changes over time, or the cache could grow without a limit.
| Use memoization | Prefer direct calculation |
|---|---|
| The function is expensive and inputs repeat. | The function is cheap or inputs are mostly unique. |
| The function is pure and produces a stable result. | The result depends on time, random values, or external state. |
| The cache has a clear size or lifetime policy. | Cached values could become stale or consume too much memory. |
Tip: Measure the function before and after caching. A cache is an optimization, not a substitute for choosing an efficient algorithm.
Summary
JavaScript memoization trades memory for speed by caching function results. It works best for expensive, pure functions with repeated inputs. Start with a small cache, use complete cache keys, and add a size or expiration policy when inputs are unbounded.