WeakSet in JavaScript: Remembering Without Keeping Things Alive
A reflection on WeakSet as a memory-aware structure, explaining how it tracks objects without owning them and avoids unintended memory retention.
At first glance, WeakSet feels like an incomplete version of Set.
You can add values. You can check if something exists.
But you canāt iterate. You canāt check its size.
And it only accepts objects.
It looks like something is missing.
But the moment you understand what WeakSet is trying to protect, those āmissing featuresā start to make sense.
Because WeakSet is not really about storing data.
Itās about remembering things without owning them.
The Problem with Set
A normal Set is straightforward:
const set = new Set()
set.add(obj)
set.has(obj)It answers a simple question:
Have I seen this value before?But thereās a hidden cost.
When you add an object to a Set, the Set keeps a reference to it.
Even if the rest of your application no longer uses that object, the Set still does.
And thatās enough to keep it alive in memory.
Over time, especially in long-running applications, this can turn into a memory leak.
Not because your logic is wrong ā but because the data structure is doing exactly what it was designed to do:
own the data it storesWhen You Donāt Want Ownership
There are situations where you donāt want to store objects permanently.
You only want to know:
Have I processed this object already?For example:
- tracking visited nodes
- marking DOM elements as processed
- preventing duplicate work
In these cases, the objectās lifecycle should not depend on your tracking system.
If the object disappears elsewhere, your tracking should disappear too.
WeakSet Changes the Relationship
This is where WeakSet comes in.
const ws = new WeakSet()
let obj = {}
ws.add(obj)Now imagine:
obj = nullIf nothing else references that object, it can be garbage collected.
And when that happens:
WeakSet forgets it automaticallyThis is the key difference.
Set keeps objects alive.
WeakSet does not.
Why Itās Called āWeakā
The word āweakā refers to the reference.
Set ā strong reference (prevents garbage collection)
WeakSet ā weak reference (does not prevent it)WeakSet doesnāt control the lifecycle of objects.
It simply observes them.
Why WeakSet Has Limitations
At first, the restrictions feel inconvenient.
But they are necessary.
Only objects are allowed:
only objects can be garbage collectedNo iteration:
entries can disappear at any timeNo size:
you canāt reliably know how many objects are still aliveThese are not missing features.
They are consequences of how WeakSet works with memory.
Where WeakSet Fits Naturally
WeakSet becomes useful when you need to track objects temporarily without affecting their lifecycle.
Tracking visited objects:
const visited = new WeakSet()
function process(obj) {
if (visited.has(obj)) return
visited.add(obj)
// do something
}Marking DOM elements:
const processed = new WeakSet()
function handle(el) {
if (processed.has(el)) return
processed.add(el)
// do something
}In both cases, once the object is no longer used elsewhere, it disappears from memory ā and from the WeakSet.
A Subtle Shift in Thinking
Most data structures are about control.
They store data and keep it alive.
WeakSet is different.
It introduces a new question:
Should I be responsible for keeping this object alive?Sometimes the answer is yes ā use Set.
Sometimes the answer is no ā use WeakSet.
Connecting the Idea
If youāve seen WeakMap, this might feel familiar.
WeakMap ā object ā value
WeakSet ā object onlyYou can even think of WeakSet as:
WeakMap where the value is always trueBut the deeper idea is the same.
Itās not about what you store.
Itās about how that storage interacts with memory.
What WeakSet Really Teaches
WeakSet introduces something thatās easy to ignore at first:
Memory is part of your design.
Not just performance ā but correctness.
When your application runs long enough, the difference between:
storing data
and
holding onto datastarts to matter.
WeakSet gives you a way to remember thingsā¦
without accidentally keeping them around forever.