Maps, Sets, WeakMap & WeakSet
Key Learning Objectives
Differentiate Map from plain JavaScript objects in key types, insertion-order iteration, and performance.
Understand Set value uniqueness, iteration semantics, and SameValueZero equality for NaN.
Master object reference identity as collection keys: understand why distinct object literals produce separate entries.
Learn the limitations and capabilities of WeakMap and WeakSet: non-enumerable, non-iterable, and garbage-collection friendly.
Implement practical memory-leak free DOM metadata associations and object-keyed caching layers.
The Interview Problem
What is logged to the console when the following Map and Set operations execute, and how do object reference identity and SameValueZero equality determine collection size and retrieval?
1const map = new Map();2const set = new Set();34const keyObj = { id: 1 };5map.set(keyObj, 'original');6map.set({ id: 1 }, 'duplicate?');7map.set(NaN, 'first-nan');8map.set(NaN, 'second-nan');910set.add(keyObj);11set.add({ id: 1 });12set.add(NaN);13set.add(NaN);1415const res1 = map.size;16const res2 = set.size;17const res3 = map.get(keyObj);18const res4 = map.get({ id: 1 });1920console.log(res1, res2, res3, String(res4));
Predict Console Output
Select the option that matches what standard ECMAScript prints to the console:
3 3 original undefined
2 2 duplicate? duplicate?
4 4 original undefined
3 3 original duplicate?
V8 Engine Execution Trace
Step 1 of 6 (Line 4)Allocates keyObj at HeapRef#1. Initializes empty Map and Set instances.
Deep Technical Breakdown
Map vs Plain Object: The Deep Architectural Differences
While plain JavaScript objects ({}) are traditionally used as key-value hash maps, ES6 Map was specifically designed for programmatic collection lookup with major advantages:
- Key Types: Object keys are coerced to strings or symbols (
obj[123]becomesobj['123']). AMapkey can be any type: objects, functions, numbers, Booleans, orNaN. - Iteration & Ordering: A
Mapstrictly guarantees insertion-order iteration over its entries viafor (const [k, v] of map). Plain object key iteration order has complex integer-index sorting rules. - Size Introspection:
map.sizeis an O(1) property lookup, whereas determining object size requires O(N)Object.keys(obj).lengtharray allocation. - Prototype Collisions: Plain objects inherit keys from
Object.prototype(e.g.,toString,constructor), risking security bugs (prototype pollution).Mapcontains only explicitly set keys.
The WeakMap & WeakSet Engine Mechanics
A WeakMap holds weak references to its keys:
- Keys Must Be Objects: Primitives are disallowed because primitives cannot be garbage-collected.
- Garbage Collection Eligibility: If an object stored as a key in a
WeakMaphas no other strong references remaining in the heap, the object becomes eligible for garbage collection. Crucially, the ECMAScript specification gives zero deterministic timing guarantees for garbage collection; the engine reclaims unreferenced heap memory at its own nondeterministic discretion. WeakMap never guarantees an immediate reclamation event. - Zero Enumeration:
WeakMaphas no.size, no.forEach(), no.keys(), and is not iterable. Exposing iterability would expose non-deterministic garbage collection timing to application code.
Practical WeakMap Use Case: DOM Metadata Attachment
const elementMetadata = new WeakMap();
function attachTooltip(domNode, tooltipText) {
elementMetadata.set(domNode, { tooltip: tooltipText, clickCount: 0 });
}
// When domNode is removed from the DOM and dereferenced by UI code,
// elementMetadata does NOT retain it in memory. It becomes eligible for GC without memory leaks!Common Traps & Mistakes
Using object literals as lookup keys in `map.get({ id: 1 })` and expecting a match. Map compares keys by reference identity (`===`), not structural value.
Attempting to iterate over a `WeakMap` or read its `.size`. WeakMap is deliberately non-iterable to avoid exposing garbage collection non-determinism.
Assuming garbage collection runs immediately when an object is dereferenced. GC is an autonomous engine heuristic with zero timing guarantees.
Storing primitive strings or numbers as `WeakMap` keys, which throws `TypeError: Invalid value used as weak map key`.
Assuming `Set` uses `===` for deduplication. `Set` uses `SameValueZero`, which correctly considers `NaN === NaN`.
FAANG Follow-Up Probes
Probe #1
How can WeakMap be used to simulate truly private instance variables in ES5/ES6 classes prior to private class fields (#)?
Probe #2
What is the difference between SameValueZero (used in Map/Set) and SameValue (used in Object.is)?
Probe #3
How does ES2023 allow non-registered Symbols (`Symbol('desc')`) as keys in WeakMap and WeakSet?
