Explain WeakMap and WeakSet with use cases.
WeakMap/WeakSet hold their keys/values WEAKLY — if nothing else references a key, it can be garbage-collected, and the entry vanishes. Keys must be objects. They're not iterable and have no size. Use cases: private data per object, caching/memoization keyed by object, and tracking objects without leaking memory.
WeakMap and WeakSet are variants of Map/Set whose defining feature is weak references — they don't keep their keys alive.
What "weak" means
A normal Map holds a strong reference to its keys: as long as the Map exists, its keys can't be garbage-collected — even if nothing else points to them. That's a memory leak if you use objects as keys and forget to delete entries.
A WeakMap holds its keys weakly: if the only reference to a key object is the WeakMap entry, the object is eligible for garbage collection — and when it's collected, the entry disappears automatically. WeakSet does the same for its values.
The constraints (consequences of being weak)
- Keys/values must be objects (and non-registered symbols) — not primitives. Primitives don't have identity to weakly hold.
- Not iterable, no
size, noclear()— you can't enumerate them. Because GC timing is non-deterministic, the contents aren't observably stable, so iteration isn't allowed. - API is minimal — WeakMap:
get/set/has/delete. WeakSet:add/has/delete.
Use cases
1. Private data per object. Associate private state with an object without putting it on the object:
const privateData = new WeakMap();
class Counter {
constructor() { privateData.set(this, { count: 0 }); }
increment() { privateData.get(this).count++; }
}When a Counter instance is GC'd, its private data goes with it — no leak, no cleanup code.
2. Caching / memoization keyed by object. Cache an expensive computation per object; when the object is gone, the cache entry is freed automatically:
const cache = new WeakMap();
function compute(obj) {
if (cache.has(obj)) return cache.get(obj);
const result = expensive(obj);
cache.set(obj, result);
return result;
}A normal Map here would pin every object forever.
3. Tracking objects without preventing cleanup. WeakSet to mark "have I already processed/seen this object?" — visited.add(node) — without keeping those objects alive.
4. Metadata for DOM nodes. Attach data to DOM elements; when the element is removed and GC'd, the metadata is released.
The mental model
Use a WeakMap/WeakSet when you want to associate data with an object for exactly as long as that object lives — and not a moment longer. The GC does your cleanup.
The framing
"They're Map/Set that reference their keys/values weakly — if nothing else holds the key object, it gets garbage-collected and the entry vanishes on its own. That's the whole point: no memory leak from forgotten entries. The trade-offs follow from that: keys must be objects, and they're not iterable and have no size, because GC timing is non-deterministic. Use them to tie data to an object's lifetime — private per-instance state, object-keyed caches that self-clean, marking objects as seen, or DOM-node metadata."
Follow-up questions
- •Why aren't WeakMap and WeakSet iterable?
- •Why must the keys be objects?
- •How would a regular Map cause a memory leak where a WeakMap doesn't?
- •How do you implement private class fields with a WeakMap?
Common mistakes
- •Trying to use primitives as WeakMap keys.
- •Expecting to iterate or get the size of a WeakMap/WeakSet.
- •Using a regular Map for object-keyed caches and leaking memory.
- •Assuming you can observe exactly when an entry is removed (GC is non-deterministic).
Performance considerations
- •The core benefit IS memory: WeakMap/WeakSet let the GC reclaim objects and their associated data instead of pinning them. They prevent the slow memory growth that object-keyed regular Maps cause in long-lived apps.
Edge cases
- •An entry's removal timing is unobservable — don't rely on it.
- •The key is still referenced elsewhere — it won't be collected.
- •Non-registered symbols are now allowed as keys (recent spec).
Real-world examples
- •Libraries storing private instance state in a WeakMap.
- •Memoization caches keyed by object that don't leak; DOM-node metadata that frees with the node.