WeakMap and WeakSet
WeakMap and WeakSet in JavaScript
Garbage-collection-friendly collections, memory leak prevention, and private data patterns.
The Museum Visitor Coat Check Tag
Standard `Map` and `Set` maintain strong references to keys and values, preventing garbage collection even if objects are discarded elsewhere. `WeakMap` and `WeakSet` hold "weak" references that do not block the GC.
Weak References to Keys
In a `WeakMap`, keys MUST be objects (or non-registered symbols). If an object key has no other references in memory, it and its associated value are automatically garbage collected.
Non-Enumerable by Design
`WeakMap` and `WeakSet` have NO `.size` property, NO `.keys()`, and NO `forEach()` iterator. Because garbage collection runs non-deterministically, the collection size cannot be observed.
Private Instance State
Store private properties in a module-scoped `WeakMap` keyed by `this`. When an instance is dereferenced, its private state is automatically garbage collected.
DOM Metadata and Caching
Ideal for attaching event count or listener metadata to DOM nodes. When the DOM element is removed from the tree, its metadata is collected without manual cleanup.
Attaching metadata to DOM nodes and encapsulating private state safely:
// Safe metadata attachment without memory leaks
const clickCountTracker = new WeakMap();
function recordButtonClick(buttonElement) {
const currentClicks = clickCountTracker.get(buttonElement) || 0;
clickCountTracker.set(buttonElement, currentClicks + 1);
return clickCountTracker.get(buttonElement);
}
// Simulating DOM node lifecycle
let fakeButton = { id: "submit-btn" };
console.log("Click 1:", recordButtonClick(fakeButton));
console.log("Click 2:", recordButtonClick(fakeButton));
// When fakeButton is unmounted from DOM and dereferenced:
fakeButton = null;
// At this point, clickCountTracker will automatically release the entry during GC!
Click 1: 1
Click 2: 2
Passing Primitive Keys to WeakMap
The Risk: `weakMap.set("user_id", data)` throws `TypeError: Invalid value used as weak map key` because primitives cannot be weakly referenced.
The Fix: Use standard `Map` for primitive keys, or ensure keys are object references.
- ✓ Keys in `WeakMap` and values in `WeakSet` MUST be objects (or registered symbols).
- ✓ Does NOT prevent Garbage Collection: entries are automatically swept when key object is unreferenced.
- ✓ Non-iterable: No `.size`, `.keys()`, `.entries()`, or `.forEach()`.
- ✓ Only provides: `.get()`, `.set()`, `.has()`, `.delete()` (or `.add()`, `.has()`, `.delete()`).
- ✓ Perfect for DOM node metadata, caching, and private instance fields.