WeakMap and WeakSet in JavaScript
- WeakMap and WeakSet hold weak references — objects can be garbage collected even when held as keys.
- Keys must be objects (or registered symbols in WeakMap) — primitives are not allowed.
- Neither is iterable — no .forEach(), no .keys(), no .size. This is intentional.
WeakMap and WeakSet hold weak references to their keys/values — if no other reference to the object exists, it can be garbage collected even if it is in a WeakMap or WeakSet. This makes them ideal for caching data associated with objects without preventing those objects from being collected. Limitation: they are not iterable.
WeakMap — Object-keyed Private Data
const privateData = new WeakMap(); class Person { constructor(name, age) { // Store private data keyed by this instance privateData.set(this, { age, secretCode: Math.random() }); this.name = name; // public } getAge() { return privateData.get(this).age; // private data not on the object } greet() { return `Hi, I'm ${this.name}, age ${this.getAge()}`; } } const alice = new Person('Alice', 30); console.log(alice.greet()); // Hi, I'm Alice, age 30 console.log(alice.age); // undefined — not a public property console.log(alice.secretCode); // undefined — truly private // When alice goes out of scope and is GC'd, privateData entry is also collected
undefined
undefined
WeakMap vs Map for Caching
// Problem: regular Map prevents garbage collection of DOM nodes const cache = new Map(); function processElement(el) { if (cache.has(el)) return cache.get(el); const result = expensiveComputation(el); cache.set(el, result); return result; } // If el is removed from the DOM, cache still holds a reference → memory leak // Solution: WeakMap — entry removed when el is GC'd const weakCache = new WeakMap(); function processElementSafe(el) { if (weakCache.has(el)) return weakCache.get(el); const result = { processed: true, timestamp: Date.now() }; weakCache.set(el, result); return result; } // Keys must be objects — not primitives const obj = {}; weakCache.set(obj, 'data'); // OK // weakCache.set('string', 'data'); // TypeError: Invalid value used as weak map key function expensiveComputation(el) { return { computed: true }; }
WeakSet — Tracking Object Membership
const visited = new WeakSet(); function processNode(node) { if (visited.has(node)) { console.log('Already processed, skipping'); return; } visited.add(node); console.log('Processing node:', node.id); // process... } const nodeA = { id: 'a', data: 'hello' }; const nodeB = { id: 'b', data: 'world' }; processNode(nodeA); // Processing node: a processNode(nodeA); // Already processed, skipping processNode(nodeB); // Processing node: b // WeakSet only has: add(), has(), delete() // No size, no iteration — by design (GC timing is unpredictable)
Already processed, skipping
Processing node: b
🎯 Key Takeaways
- WeakMap and WeakSet hold weak references — objects can be garbage collected even when held as keys.
- Keys must be objects (or registered symbols in WeakMap) — primitives are not allowed.
- Neither is iterable — no .forEach(), no .keys(), no .size. This is intentional.
- Primary use case: caching metadata about objects without preventing their collection.
- WeakRef and FinalizationRegistry (ES2021) are the more explicit tools if you need to react to GC.
Interview Questions on This Topic
- QWhat is the difference between a Map and a WeakMap in JavaScript?
- QWhy are WeakMap and WeakSet not iterable?
- QGive a practical use case for WeakMap.
Frequently Asked Questions
When should I use WeakMap over Map?
Use WeakMap when the keys are DOM nodes or objects whose lifetime you do not control, and you want the associated data to be automatically cleaned up when the key is collected. If you need to iterate entries, check size, or use primitive keys, use Map.
Why can't WeakMap and WeakSet be iterated?
Because the garbage collector can remove entries at any time — there is no guaranteed order or set of entries at any given moment. Exposing iteration would either force the GC to not collect entries (defeating the purpose) or produce inconsistent results.
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.