Map, Set, WeakMap and WeakRef: choosing the right collection
Map takes any key and keeps order; Set keeps unique values and now has union and intersection; WeakMap keys objects without keeping them alive.
Comes up in: JavaScript, Coding, DSA
Learn#
Rahul counts visits per user with a plain object: visits[user] = 1. Every user ends up under the same key, "[object Object]", because plain objects turn keys into strings.
A Map fixes that. Its keys can be any value — objects, numbers, functions — compared by identity. It keeps insertion order, has .size, and has no inherited keys like toString to collide with.
A Set holds unique values. Since ES2025 it also has union, intersection, difference and more.
const visits = new Map();
const user = { id: 7 };
visits.set(user, 3).set("guest", 1).set(42, 0);
console.log(visits.get(user), visits.size, [...visits.keys()].map(String));
const plain = {};
plain[user] = 3;
console.log(Object.keys(plain), "toString" in plain, visits.has("toString"));
const a = new Set([1, 2, 3, 3]), b = new Set([2, 3, 4]);
console.log(a.size, [...a.union(b)], [...a.intersection(b)], [...a.difference(b)]);Output (verified)
3 3 [ '[object Object]', 'guest', '42' ] [ '[object Object]' ] true false 3 [ 1, 2, 3, 4 ] [ 2, 3 ] [ 1 ]
A WeakMap only takes objects as keys and holds them by weak reference: the entry does not keep the key alive. When the object is gone, so is its entry. That makes WeakMaps right for caches and extra data attached to objects you do not own, like DOM nodes. In exchange, you cannot list or count their entries.
page
- <div id=card>
Cache
- card → layout data
cache (Map)
empty
cache (WeakMap)
empty
A Map cache keyed by DOM node: the map holds the node strongly.
Read the steps as text
- A Map cache keyed by DOM node: the map holds the node strongly.
- The card is removed from the page. A Map still points to it, so it stays in memory.
- With a WeakMap, the entry does not keep the key alive.
- Nothing else references the card, so the garbage collector can free it — and the entry disappears.
Predict#
Predict first
const m = new Map(); m.set({ id: 1 }, 'a'); What is m.get({ id: 1 })?
Map compares object keys by identity, not by content. The second { id: 1 } is a new object, so there is no match. Keep a reference to the key, or use a primitive key such as the ID.
Interview angle#
Say it like this — about 30 seconds
“I use a Map when keys are not plain strings, when I add and remove keys often, when I need the size or guaranteed insertion order, or when keys come from users — no prototype collisions. A Set is for unique values, and now has union, intersection and difference. A WeakMap takes object keys without keeping them alive, so it is ideal for caches or metadata attached to DOM nodes or objects I don’t own. It is not iterable, by design.”
Follow-up When would you use a Map instead of a plain object?
.size or order, or untrusted keys like __proto__. Objects remain best for fixed-shape records and JSON.Follow-up Why can't you iterate a WeakMap?
Follow-up Should you use WeakRef to build a cache?
Practice#
On your own
Write dedupeBy with a Set, and rewrite makeNodeCache with a WeakMap — the starter’s object turns every key into "[object Object]".
Done when
dedupeBy(users, (u) => u.email)keeps the first user per email, in order.get(obj)callscomputeonce per object and returns separate results for different objects.get(42)throws a TypeError (WeakMap keys must be objects).
Remember#
Try to answer each card before you open it. Then add them to your reviews.
What happens to object keys on a plain object?
They are turned into strings, like '[object Object]'.
How does Map compare object keys?
By identity (SameValueZero), not by content.
What makes a WeakMap weak?
Its entries do not keep their object keys alive.
Name three ES2025 Set methods.
union, intersection, difference (also symmetricDifference, isSubsetOf…).
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
Map: any key, ordered, sized. Set: unique values. WeakMap/WeakSet: object keys held weakly, not iterable. Use objects for records, Map for dictionaries.
Check yourself: Can a WeakMap key be a string?
No. Keys must be objects (or non-registered symbols).
How it works underneathSenior rounds
Map and Set use SameValueZero, so NaN works as a key and +0/-0 are the same (JS.05.03). The ES2025 Set methods accept any “set-like” argument with size, has and keys Source: MDN: Set composition.
Check yourself: Which equality does Map use for keys?
SameValueZero.
Edge cases and trapsWhere people slip
WeakRef holds an object without keeping it alive; deref() returns it or undefined. FinalizationRegistry runs a callback after collection — maybe late, maybe never. Do not put essential logic in either Source: MDN: WeakRef — avoid where possible.
Check yourself: Is a FinalizationRegistry callback guaranteed to run?
No. It may run late or never.
In productionStaff-level answers
An unbounded Map cache is a memory leak with good intentions. Use WeakMap when entries should live as long as their object key, and an LRU with a size limit when keys are strings (JS.16.03). Convert to plain objects only at the JSON boundary: Object.fromEntries(map).
Check yourself: Why might a Map-based cache grow forever?
Entries are never evicted; it needs a size limit or WeakMap keys.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- When would you use a Map instead of a plain object?
- What is a WeakMap and when is it useful?