How WeakSet Tracks Object References in JavaScript
JavaScript’s WeakSet is a specialized collection that
holds unique objects without preventing the JavaScript engine from
reclaiming their memory. This article explains how WeakSet
leverages weak references, how the garbage collector determines object
reachability, why WeakSet is not iterable, and how it
safely tracks objects without creating memory leaks.
Strong References vs. Weak References
In standard JavaScript collections like Array or
Set, adding an object creates a strong
reference. As long as the collection exists in memory, the
objects inside it cannot be garbage collected, even if all other
variables pointing to them are set to null or go out of
scope.
let user = { name: "Alice" };
const strongSet = new Set();
strongSet.add(user);
user = null; // The object { name: "Alice" } remains in memory because strongSet holds a strong reference.A WeakSet, by contrast, holds only weak
references to objects. A weak reference does not prevent the
garbage collector from disposing of the referenced object if no other
strong references to it exist.
let user = { name: "Alice" };
const weakSet = new WeakSet();
weakSet.add(user);
user = null; // The object { name: "Alice" } is now eligible for garbage collection.How the Garbage Collector Treats WeakSet
Modern JavaScript engines (like V8 in Chrome and Node.js, SpiderMonkey in Firefox, and JavaScriptCore in Safari) use a Mark-and-Sweep garbage collection algorithm to manage memory.
- Roots Definition: The engine identifies “root” objects that are always reachable (global variables, currently executing functions, call stacks).
- Traversing References: The collector traverses the graph of references originating from the roots, marking every reachable object as alive.
- Weak Reference Exclusion: When the collector
inspects a
WeakSet, it does not count the links from theWeakSetto its elements as valid paths for reachability. - Sweeping: If an object stored in a
WeakSethas no incoming strong references originating from any root, the garbage collector treats it as dead and reclaims its memory. The corresponding entry inside theWeakSetis automatically invalidated.
Engine-Level Implementation: Ephemerons
Under the hood, JavaScript engines implement weak collections using structures similar to ephemerons or hidden internal properties.
Instead of maintaining an independent, persistent list of pointers
that force objects to stay alive, the WeakSet is
conceptually attached to the lifecycle of the objects it stores:
- When you check
weakSet.has(obj), the engine queries whether the association exists for that specific living object reference. - Once the object is destroyed by the garbage collector, the association disappears without needing a manual cleanup step from the developer.
The Cost of Non-Determinism: Why WeakSet Has No Iteration
Because garbage collection is non-deterministic—meaning it runs at unpredictable intervals determined by memory pressure and CPU idle time—the exact moment an object is removed from memory cannot be predicted by code.
To prevent non-deterministic program behavior: - WeakSet
does not have a .size property. - WeakSet does
not implement keys(), values(),
entries(), or the Symbol.iterator method. -
WeakSet cannot be looped over using for...of
or .forEach().
If iteration were allowed, the number and identity of elements in the set would change randomly depending on whether the garbage collector had executed, leading to inconsistent application state.
Only Objects Allowed
A WeakSet can only contain objects (and non-registered
symbols in newer ECMAScript specifications). Primitive types such as
numbers, strings, or booleans cannot be stored because primitives are
immutable values passed by value, not tracked references managed by the
garbage collector.
Common Use Cases
WeakSet is primarily used to tag or classify objects
without modifying them or leaking memory:
- Tracking Object State: Marking objects as “processed” or “validated” across an application lifecycle without modifying the original object structure.
- Access Control: Maintaining lists of authorized DOM elements, instances, or event handlers that should automatically cease to be tracked once removed from the DOM or application scope.