Back to JavaScript
JavaScript
medium
mid

What are WeakMap and WeakSet in JavaScript, and what are their 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.

4 min read·~6 min to think through

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, no clear() — 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:

js
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:

js
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.

Senior engineer discussion

Seniors explain weak references and GC eligibility as the defining property, derive the constraints (object keys, non-iterable, no size) from it, and give concrete leak-avoidance use cases — private data, self-cleaning caches, object tracking.

Related questions