Memoization in JavaScript

Memoization is a powerful optimization technique in JavaScript that boosts performance by caching the results of expensive function calls and reusing them when the same inputs occur again. By avoiding redundant computations, memoization is ideal for recursive algorithms, complex calculations, or functions called repeatedly with identical inputs. In this blog, we’ll explore what memoization is, how it works, and demonstrate its power with practical examples. Let’s dive into making your JavaScript code faster and smarter!
What is Memoization?
Memoization is a technique that stores the results of costly function calls in a cache, retrieving them when the same inputs are provided again. This trade-off—using memory to store results in exchange for faster execution—is particularly effective for pure functions (functions that produce the same output for the same input without side effects) and recursive algorithms with overlapping subproblems.
Key Benefits
Performance: Eliminates redundant calculations, reducing time complexity for expensive operations.
Use Cases: Optimizes recursive functions (e.g., Fibonacci, factorial), API calls, or dynamic programming problems.
Trade-Off: Increases memory usage due to caching, which requires careful management for large input sets.
How Memoization Works
Memoization involves four steps:
Initialize a Cache: Use an object, array, or Map to store input-output pairs.
Check the Cache: Before computing, verify if the result for the given input is already cached.
Compute and Store: If the result isn’t cached, calculate it, store it in the cache, and return it.
Return Cached Result: If the result exists in the cache, return it directly, skipping computation.
In JavaScript, memoization is often implemented using closures within higher-order functions, where an outer function creates a cache and returns an inner function that uses it. This ensures the cache persists across calls, as we’ll see in the examples.
Practical Examples of Memoization
Let’s explore examples that showcase memoization in action, from optimizing recursive algorithms to creating reusable memoizers.
Example 1: Memoized Fibonacci Function
The Fibonacci sequence, where each number is the sum of the two preceding ones, is computationally expensive due to redundant recursive calls. Memoization drastically improves its performance.
// Non-memoized Fibonacci (slow for large n)
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
// Memoized Fibonacci
function memoizedFib() {
const cache = {};
return function fib(n) {
if (n in cache) return cache[n]; // Return cached result
if (n <= 1) return n;
cache[n] = fib(n - 1) + fib(n - 2); // Compute and cache
return cache[n];
};
}
const fibFast = memoizedFib();
console.log(fibFast(40)); // 102334155 (fast)
console.log(fibFast(40)); // 102334155 (cached, instant)
console.log(fibFast(41)); // fib(41) needs fib(40) + fib(39), both already cached!
How It Works:
Non-Memoized: The basic
fib
function recalculates values (e.g.,fib(39)
) multiple times, leading to exponential time complexity (O(2^n)).Memoized:
memoizedFib
creates a closure over acache
object. The innerfib
function checkscache
before computing. ForfibFast(40)
, it caches intermediate results (e.g.,cache[39]
,cache[38]
), reducing complexity to O(n).Closure and Higher-Order Function:
memoizedFib
is a higher-order function that returnsfib
, which uses a closure to maintaincache
. This ensures all calls tofibFast
share the same cache, enabling instant retrieval for repeated inputs.Output: The first call computes and caches results; the second call retrieves
cache[40]
instantly.
Example 2: Generic Memoization Function
A generic memoizer wraps any function to add memoization, handling multiple arguments by serializing them into a cache key.
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args); // Serialize arguments as cache key
if (key in cache) return cache[key];
cache[key] = fn(...args);
return cache[key];
};
}
// Example: Expensive computation
function expensiveCalculation(a, b) {
console.log(`Computing ${a} + ${b}...`);
return a + b; // Simulating an expensive operation
}
const memoizedCalc = memoize(expensiveCalculation);
console.log(memoizedCalc(2, 3)); // Computing 2 + 3 ... 5
console.log(memoizedCalc(2, 3)); // 5 (cached, no recomputation)
console.log(memoizedCalc(4, 5)); // Computing 4 + 5 ... 9
How It Works:
Generic Memoizer:
memoize
is a higher-order function that takes any functionfn
and returns a memoized version, using a closure to maintaincache
.Cache Key:
JSON.stringify(args)
creates a unique key for argument combinations (e.g.,[2, 3]
becomes"[2,3]"
).Behavior: The first
memoizedCalc(2, 3)
computes and caches5
. The second call retrieves it fromcache
. A call with4, 5
computes and caches9
.Use Case: Versatile for any pure function, such as API responses or complex calculations.
Key Considerations
Memory Usage: Caching consumes memory, especially for functions with many unique inputs. Consider cache eviction strategies (e.g., limiting cache size) for large datasets.
Pure Functions: Memoization is most effective for pure functions, as side effects can lead to inconsistent cached results.
Argument Serialization: Using
JSON.stringify
for cache keys may fail with non-serializable inputs (e.g., functions, circular objects). Custom key generation may be needed.Thread Safety: JavaScript’s single-threaded nature eliminates thread safety concerns, but ensure the cache is scoped properly using closures.
Practical Applications
Recursive Algorithms: Optimize functions like Fibonacci or factorial by caching intermediate results.
API Calls: Cache responses for repeated API requests with identical parameters to reduce network overhead.
Dynamic Programming: Solve problems with overlapping subproblems, such as shortest path algorithms.
UI Rendering: Cache computed values in web applications to enhance rendering performance.
Thank you for reading!
Try memoization in your projects to unlock significant speed improvements, and share your favourite applications in the comments.
Happy coding! 🚀
Subscribe to my newsletter
Read articles from Deepthi Purijala directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Deepthi Purijala
Deepthi Purijala
Full Stack Developer with hands-on experience of more than 1 year. Proficient in both Back-end and Front-end technologies, with a strong commitment to delivering high-quality code