WeakMap and WeakSet
JavaScript has weak versions of Map and Set. They hold their keys or values weakly, which means they do not prevent garbage collection. When an object is no longer referenced anywhere else, it can be cleaned up automatically, and its entry in the weak collection goes with it.
WeakMap
A WeakMap is a Map where keys are held weakly.
Key Characteristics
- Keys must be objects (or non-registered symbols in modern engines)
- Registered symbols (
Symbol.for(...)) are not valid weak keys - Not iterable (no
forEach,keys(),values(), orsize) - Entries can be garbage collected when the key object is no longer referenced
const weakMap = new WeakMap();
let user = { name: "Alice" };
weakMap.set(user, { visits: 10 });
console.log(weakMap.get(user)); // { visits: 10 }
user = null; // The entry can now be garbage collected
Use Case: Private Data
WeakMap is commonly used to store private data associated with objects:
const privateData = new WeakMap();
class Person {
constructor(name, ssn) {
this.name = name;
privateData.set(this, { ssn });
}
getSSN() {
return privateData.get(this).ssn;
}
}
const alice = new Person("Alice", "123-45-6789");
console.log(alice.name); // "Alice"
console.log(alice.getSSN()); // "123-45-6789"
console.log(alice.ssn); // undefined - not directly accessible
When the Person instance is garbage collected, its private data is automatically cleaned up.
Use Case: Caching
WeakMap works well for caching computed results:
const cache = new WeakMap();
function expensiveOperation(obj) {
if (cache.has(obj)) {
console.log("Cache hit");
return cache.get(obj);
}
console.log("Computing...");
const result = { computed: obj.value * 2 };
cache.set(obj, result);
return result;
}
const data = { value: 21 };
expensiveOperation(data); // "Computing..." → { computed: 42 }
expensiveOperation(data); // "Cache hit" → { computed: 42 }
WeakSet
A WeakSet is a Set where values are held weakly.
Key Characteristics
- Values must be objects (or non-registered symbols in modern engines)
- Registered symbols (
Symbol.for(...)) are not valid weak values - Not iterable (no
forEachorsize) - Values can be garbage collected when no longer referenced elsewhere
const weakSet = new WeakSet();
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null; // The entry can now be garbage collected
Use Case: Tracking Objects
WeakSet is useful for tracking which objects have been processed:
const processed = new WeakSet();
function processOnce(obj) {
if (processed.has(obj)) {
console.log("Already processed");
return;
}
console.log("Processing:", obj.id);
processed.add(obj);
}
const item = { id: 42 };
processOnce(item); // "Processing: 42"
processOnce(item); // "Already processed"
Use Case: Marking Objects
const marked = new WeakSet();
function markAsVisited(node) {
marked.add(node);
}
function hasBeenVisited(node) {
return marked.has(node);
}
Summary
| Collection | Keys/Values | Iterable | Use Case |
|---|---|---|---|
Map |
Any type -> Any | Yes | Key-value pairs with non-string keys |
Set |
Unique values | Yes | Unique collections, membership testing |
WeakMap |
Objects/non-registered symbols -> Any | No | Private data, caching without leaks |
WeakSet |
Objects/non-registered symbols | No | Tracking objects without preventing GC |