WeakMap and WeakSet are special versions of Map and Set. You will not need them often, but they solve a real problem: memory leaks from collections that keep objects alive.
The problem
A normal Map or Set holds a strong reference to its keys. As long as an object is a key, the garbage collector cannot free it, even if nothing else uses it.
const cache = new Map();
function process(element) {
cache.set(element, expensiveResult(element));
}
// If the element is removed from the page, the Map STILL holds it. Memory is never freed.
Weak references
A WeakMap holds its keys weakly. If the key object is not used anywhere else, it can be garbage collected, and its entry disappears automatically.
const metadata = new WeakMap();
let user = { name: "Maya" };
metadata.set(user, { visits: 3 });
console.log(metadata.get(user)); // → { visits: 3 }
console.log(metadata.has(user)); // → true
user = null; // nothing refers to the object now: it can be collected, and so can its entry
The rules
WeakMap | WeakSet | |
|---|---|---|
| Keys / values | objects only (and non-registered symbols) | objects only |
| Methods | get, set, has, delete | add, has, delete |
Iteration / size / clear | not available | not available |
You cannot loop over them or ask how many entries they hold, because the garbage collector may remove entries at any time, and the result would be unpredictable.
Practical uses
1. Attach data to objects without changing them.
const clickCounts = new WeakMap();
function recordClick(element) {
clickCounts.set(element, (clickCounts.get(element) ?? 0) + 1);
}
const button = {};
recordClick(button);
recordClick(button);
console.log(clickCounts.get(button)); // → 2
When the element goes away, so does its count.
2. A cache keyed by objects.
const cache = new WeakMap();
function areaOf(shape) {
if (cache.has(shape)) return cache.get(shape);
const area = shape.width * shape.height;
cache.set(shape, area);
return area;
}
const rect = { width: 3, height: 4 };
console.log(areaOf(rect)); // → 12
console.log(areaOf(rect)); // → 12 (cached)
3. Marking objects as processed (WeakSet).
const seen = new WeakSet();
function once(obj) {
if (seen.has(obj)) return "already handled";
seen.add(obj);
return "handled now";
}
const item = {};
console.log(once(item)); // → handled now
console.log(once(item)); // → already handled
4. Private data in older code, before #private fields existed. See Private Fields.
Do not rely on cleanup timing
You cannot observe exactly when an entry is removed, and JavaScript gives no guarantee about when garbage collection runs. Treat weak collections as a way to avoid leaks, not as a timer.
When not to use them
If you need to list the entries or count them, use Map or Set. If your keys are strings or numbers, weak collections do not apply at all.