Skip to main content

How do you implement function memoization?

1. Basic implementation (for one function with primitive arguments)

javascript
function memoize(fn) { const cache = {}; return function (...args) { const key = JSON.stringify(args); // build a key from the arguments if (key in cache) { console.log('Taking from cache:', key); return cache[key]; } console.log('Computing:', key); const result = fn(...args); cache[key] = result; return result; }; }

Usage example:

javascript
function slowAdd(a, b) { // simulate heavy computation for (let i = 0; i < 1e8; i++); return a + b; } const memoAdd = memoize(slowAdd); console.log(memoAdd(2, 3)); // Computing console.log(memoAdd(2, 3)); // Taking from cache console.log(memoAdd(4, 5)); // Computing

Now repeated calls with the same arguments are not recomputed, they are simply pulled from memory.


2. A universal implementation (with Map instead of an object)

It is better to use Map, because it is faster and more reliable for keys of any structure.

javascript
function memoize(fn) { const cache = new Map(); return function (...args) { const key = JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } const result = fn(...args); cache.set(key, result); return result; }; }

Benefit: you can safely cache values even for complex arguments (arrays, objects).


3. An advanced version with a cache size limit (LRU cache)

So the cache does not grow forever and does not "eat" memory.

javascript
function memoize(fn, limit = 5) { const cache = new Map(); return function (...args) { const key = JSON.stringify(args); if (cache.has(key)) { // update the usage order const value = cache.get(key); cache.delete(key); cache.set(key, value); return value; } const result = fn(...args); cache.set(key, result); // if the cache is too big, remove the oldest entry if (cache.size > limit) { const oldestKey = cache.keys().next().value; cache.delete(oldestKey); } return result; }; }

Now the cache is a "sliding" one: it stores the last N calls, which is useful for real applications.


4. A real-world example, memoizing a recursive function (fibonacci)

javascript
function memoize(fn) { const cache = {}; return function (n) { if (n in cache) return cache[n]; const result = fn(n); cache[n] = result; return result; }; } const fib = memoize(function f(n) { if (n <= 1) return n; return f(n - 1) + f(n - 2); }); console.log(fib(40)); // Fast, despite the recursion

Without memoization this would take tens of millions of calls, but with the cache, just 40.


5. An implementation supporting asynchronous functions

When you need to cache the results of fetch, axios, db.query, and so on.

javascript
function memoizeAsync(fn) { const cache = new Map(); return async function (...args) { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key); const promise = fn(...args).then(result => { cache.set(key, result); return result; }); cache.set(key, promise); return promise; }; }

Example:

javascript
const fetchUser = memoizeAsync(async (id) => { const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`); return res.json(); }); await fetchUser(1); // first time, an HTTP request await fetchUser(1); // second time, instant, from the cache

6. When and where to use memoization

ScenarioFits?Why
Expensive computationsYesSpeeds up repeat calls
Repeating argumentsYesThe cache pays off
Different arguments every timeNoThe cache is useless
HTTP requests, a databaseCautionOK if the data rarely changes
Large dataCautionWatch memory usage

Summary

Memoization is caching a function's results to speed up repeat calls. In JS it is implemented through a closure, a store (Map/Object), and serializing the arguments (JSON.stringify).

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.