Problem Statement
What is memoization in JavaScript?
Explanation
Memoization caches the results of expensive function calls and returns cached result when same inputs occur again.
It trades memory for speed. Store results of previous calls and look them up instead of recalculating.
Memoization only works with pure functions. Same input must always produce same output.
Common use cases include recursive calculations like Fibonacci, complex data transformations, and API calls.
JavaScript engines do not automatically memoize. You must implement it manually.
Understanding memoization shows advanced optimization knowledge and functional programming concepts.
Code Solution
SolutionRead Only
// BASIC MEMOIZATION
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (key in cache) {
console.log('From cache');
return cache[key];
}
console.log('Computing...');
const result = fn(...args);
cache[key] = result;
return result;
};
}
// EXAMPLE - Expensive calculation
function slowSquare(n) {
// Simulate expensive operation
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result = n * n;
}
return result;
}
const memoizedSquare = memoize(slowSquare);
console.log(memoizedSquare(5)); // Computing... 25 (takes time)
console.log(memoizedSquare(5)); // From cache 25 (instant!)
console.log(memoizedSquare(10)); // Computing... 100
console.log(memoizedSquare(5)); // From cache 25
// FIBONACCI - Classic example
// Without memoization (VERY SLOW)
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// fibonacci(40) takes several seconds!
// With memoization (FAST)
const memoizedFib = memoize(function(n) {
if (n <= 1) return n;
return memoizedFib(n - 1) + memoizedFib(n - 2);
});
// memoizedFib(40) is instant!
console.log(memoizedFib(40)); // 102334155
// ALTERNATIVE: Closure-based memoization
function fibonacciMemoized() {
const cache = {};
return function fib(n) {
if (n in cache) return cache[n];
if (n <= 1) return n;
cache[n] = fib(n - 1) + fib(n - 2);
return cache[n];
};
}
const fib = fibonacciMemoized();
console.log(fib(50)); // Fast!
// MAP-BASED MEMOIZATION
function memoizeWithMap(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;
};
}
// MEMOIZATION WITH WEAKMAP (for object keys)
function memoizeObjects(fn) {
const cache = new WeakMap();
return function(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = fn(obj);
cache.set(obj, result);
return result;
};
}
const processObject = memoizeObjects((obj) => {
// Expensive processing
return Object.keys(obj).length;
});
// LIMITED CACHE SIZE
function memoizeWithLimit(fn, limit = 100) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn(...args);
// Remove oldest entry if limit reached
if (cache.size >= limit) {
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, result);
return result;
};
}
// PRACTICAL EXAMPLES
// API calls
const fetchUser = memoize(async (id) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
});
// Same user requested multiple times: only 1 API call
await fetchUser(1); // Makes API call
await fetchUser(1); // Returns cached result
// Complex calculations
const calculateDistance = memoize((x1, y1, x2, y2) => {
return Math.sqrt(
Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)
);
});
// Data transformations
const transformData = memoize((data) => {
return data.map(item => ({
...item,
processed: expensiveOperation(item)
}));
});
// FACTORIAL WITH MEMOIZATION
const factorial = memoize(function(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
});
console.log(factorial(100)); // Fast!
// WHEN TO USE MEMOIZATION
// Use for:
// - Pure functions (same input = same output)
// - Expensive calculations
// - Recursive algorithms
// - API calls with same parameters
// - Complex data transformations
// Don't use for:
// - Functions with side effects
// - Random or time-dependent results
// - Functions called only once
// - Very simple calculations
// - Functions with large memory footprint
// MEMOIZATION VS CACHING
// Memoization: automatic caching based on inputs
// Caching: manual storage and retrieval
// MEMORY CONSIDERATIONS
// Memoization uses memory to store results
// Clear cache periodically if needed
function memoizeWithExpiry(fn, ttl = 60000) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.value;
}
const result = fn(...args);
cache.set(key, {
value: result,
timestamp: Date.now()
});
return result;
};
}