Trading memory for speed by remembering what a function already computed.
Memoization caches the result of a function call keyed by its arguments, so calling it again with the same arguments returns the cached value instantly instead of recomputing it. It only works correctly for pure functions — if a function's output can change for the same input (depends on external state, time, or randomness), caching it produces stale, incorrect results, which is the most common mistake in naive memoization implementations.
The tricky part in practice is the cache key. Primitive arguments are easy to key with something like JSON.stringify(args), but that breaks down for objects (key order isn't guaranteed, and deep equality isn't free to check) and doesn't scale for functions with many possible argument combinations, since the cache grows unbounded unless you add eviction. Using a Map or WeakMap instead of a plain object avoids prototype pollution issues and, with WeakMap, lets cached entries for object keys be garbage collected once nothing else references them.
What you'll walk away knowing