Weak collections hold their keys weakly: if nothing else references a key object, it can be garbage-collected and its entry silently disappears.
Map / Set | WeakMap / WeakSet | |
|---|---|---|
| Keys | Anything | Objects (and non-registered symbols) only |
| Keeps key alive? | Yes — strong reference | No — weak reference |
Iterable / size? | Yes | No (contents depend on the GC) |
| Methods | Full API | get/set/has/delete · add/has/delete |
Use case: private data / metadata per object
const privateData = new WeakMap();
class Person {
constructor(name, ssn) {
this.name = name;
privateData.set(this, { ssn }); // disappears when the Person is collected
}
lastFour() { return privateData.get(this).ssn.slice(-4); }
}
const p = new Person("Asha", "123-45-6789");
console.log(p.lastFour(), p);6789 Person { name: 'Asha' }Use case: caching without leaks
const cache = new WeakMap();
function expensiveSummary(obj) {
if (cache.has(obj)) return cache.get(obj) + " (cached)";
const result = `keys=${Object.keys(obj).length}`;
cache.set(obj, result);
return result;
}
const report = { a: 1, b: 2 };
console.log(expensiveSummary(report));
console.log(expensiveSummary(report));keys=2
keys=2 (cached)WeakSet: tagging objects
const visited = new WeakSet();
function visit(node) {
if (visited.has(node)) return "already visited";
visited.add(node);
return "visiting";
}
const node = {};
console.log(visit(node), "/", visit(node));
try {
visited.add("string");
} catch (e) {
console.log(e.message);
}visiting / already visited
Invalid value used in weak setWeakRef and FinalizationRegistry (ES2021)
let big = { data: "large object" };
const ref = new WeakRef(big);
console.log(ref.deref()?.data); // still alive
big = null; // now only weakly reachable — may be collected later
const registry = new FinalizationRegistry((label) => console.log("collected", label));
registry.register({}, "temp object");large objectWhy can't you iterate a WeakMap?