Compile Ready
Module 11 · Advanced JavaScript

Memoization

Advanced14m read24m practice38m total
MemoizationCachingMapDynamic Programming

Introduction

Memoization caches the result of a function call so repeated calls with the same inputs can return instantly. It is one of the most common optimization patterns in JavaScript interviews because it turns repeated work into a cache lookup.

A complete answer also discusses key generation, purity, memory growth, invalidation, and whether arguments can be serialized safely.

Why This Matters

Memoization powers dynamic programming, derived selectors, expensive formatting, search suggestions, compiler caches, and API-layer deduplication. It tests both implementation skill and performance judgment.

Theory

What can be memoized

Memoization is safest for pure functions: the same arguments always produce the same result and the function has no important side effects. If the function depends on time, random values, mutable external state, or network data, caching may return stale results.

Map-based cache

A Map is a better default than a plain object because it avoids prototype collisions, has a clear has method, and preserves insertion order for LRU eviction. For primitive interview inputs, JSON.stringify(args) is a common key.

Serialization trade-offs

JSON.stringify is convenient but imperfect. It drops some values, cannot serialize functions or symbols, throws on cycles, and treats object property order as part of the key. Production caches often accept a custom resolver or use nested maps keyed by identity.

Cache growth

A memoized function can leak memory if the cache grows forever. Stronger versions expose clear, enforce maxSize, or use time-based expiration.

Visual Diagrams

Memoized call flow
call fn(2, 3)
   |
serialize args -> [2,3]
   |
cache has key? -- yes --> return cached result
   |
  no
   |
compute original function
   |
store result in Map
   |
return result

Only cache misses run the expensive function.

Code Examples

Map-based memoize

The default key uses serialized arguments. A resolver can replace that for custom keys.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1function memoize(fn) {
2 var cache = new Map();
3 return function () {
4 var args = Array.prototype.slice.call(arguments);
5 var key = JSON.stringify(args);
6 if (cache.has(key)) {
7 console.log('hit ' + key);
8 return cache.get(key);
9 }
10 console.log('miss ' + key);
11 var result = fn.apply(this, args);
12 cache.set(key, result);
13 return result;
14 };
15}
16
17var add = memoize(function (a, b) {
18 console.log('compute');
19 return a + b;
20});
21
22console.log(add(2, 3));
23console.log(add(2, 3));
24console.log(add(3, 2));

Coding Exercises

Memoize with a maximum cache size

Hard

Implement memoize(fn, options) using a Map. Use JSON.stringify(args) by default, allow an optional resolver, and evict the least recently used entry when maxSize is exceeded.

Interview Questions

1When is memoization unsafe?

It is unsafe when the function is not pure: external mutable state, current time, random values, network data, or important side effects can make cached answers incorrect.

Asked at:GoogleAmazonNetflix

Follow-ups

  • How would you prevent unbounded memory growth?
  • How would you memoize object arguments by identity?
2Why use `Map` instead of a plain object for a cache?

Map avoids prototype-key collisions, has reliable key APIs, preserves insertion order for eviction, and communicates key-value cache semantics clearly.

Quiz

1. What is the biggest weakness of `JSON.stringify(args)` as a memoization key?

Summary

  • Memoization caches function results by argument key.
  • It works best for pure functions with stable inputs and outputs.
  • A `Map` plus serialized arguments is the standard interview implementation.
  • Production-grade caches need eviction, invalidation, and better key strategies.

Cheat Sheet

Pattern: key args → check cache → compute on miss → store result.

Default key: JSON.stringify(args) for primitive inputs.

Use Map: safe keys, insertion order, clear API.

Watch out: impure functions, cycles, object identity, unbounded growth.