JavaScript WeakMap and WeakSet
WeakMap and WeakSet are special versions of Map and Set that hold weak references to objects. A weak reference means: if no other part of the program holds on to an object, JavaScript is free to delete it from memory — even if the object is still in a WeakMap or WeakSet. This prevents memory leaks in long-running applications.
Why "Weak"?
In a regular Map, keys are held strongly — the object stays in memory as long as the Map exists. In a WeakMap, keys are held weakly — when the object is no longer referenced anywhere else, the garbage collector removes it automatically, and the WeakMap entry disappears with it.
Diagram: Strong vs Weak Reference
Regular Map: user object ◄─── Map (strong ref) ◄─── code As long as Map exists → user object stays in memory WeakMap: user object ◄─── WeakMap (weak ref) user object ◄─── code (strong ref) When code stops referencing user: → garbage collector removes user object → WeakMap entry disappears too (automatically)
WeakMap
A WeakMap is a key-value store where keys must be objects (not primitives). Values can be anything.
Creating and Using WeakMap
let weakMap = new WeakMap();
let user1 = { name: "Ravi" };
let user2 = { name: "Priya" };
weakMap.set(user1, { role: "admin" });
weakMap.set(user2, { role: "editor" });
console.log(weakMap.get(user1)); // { role: "admin" }
console.log(weakMap.has(user2)); // true
weakMap.delete(user2);
console.log(weakMap.has(user2)); // false
WeakMap Methods
| Method | What it Does |
|---|---|
set(key, value) | Stores a value for the given object key |
get(key) | Retrieves the value for the key |
has(key) | Returns true if the key exists |
delete(key) | Removes the entry |
WeakMap has NO size, NO keys(), NO forEach(). You cannot iterate over it. This is intentional — you should not need to loop over weakly held data.
WeakMap: Automatic Cleanup
let weakMap = new WeakMap();
let session = { userId: 42 };
weakMap.set(session, { token: "abc123" });
// Later, session is no longer needed
session = null; // the original object has no more strong references
// Garbage collector eventually removes the object
// The weakMap entry disappears on its own — no memory leak
Diagram: WeakMap Cleanup
Before:
session variable ──► { userId: 42 }
weakMap ──► { userId: 42 } → { token: "abc123" }
After session = null:
session variable ──► null
{ userId: 42 } has NO strong references left
Garbage collector removes it
weakMap entry is gone too
Real Use Case: Attaching Private Data to Objects
WeakMap lets you associate private metadata with an object without modifying the object itself.
const privateData = new WeakMap();
class BankAccount {
constructor(owner, balance) {
privateData.set(this, { balance });
this.owner = owner;
}
deposit(amount) {
let data = privateData.get(this);
data.balance += amount;
}
getBalance() {
return privateData.get(this).balance;
}
}
let acc = new BankAccount("Anjali", 1000);
acc.deposit(500);
console.log(acc.getBalance()); // 1500
console.log(acc.balance); // undefined — truly private
WeakSet
A WeakSet is like a Set — but it only stores objects (not primitives), and it holds them weakly. When an object has no other strong references, it is removed from the WeakSet automatically.
Creating and Using WeakSet
let weakSet = new WeakSet();
let task1 = { id: 1, name: "Login" };
let task2 = { id: 2, name: "Signup" };
weakSet.add(task1);
weakSet.add(task2);
console.log(weakSet.has(task1)); // true
weakSet.delete(task1);
console.log(weakSet.has(task1)); // false
WeakSet Methods
| Method | What it Does |
|---|---|
add(object) | Adds the object |
has(object) | Checks if the object exists |
delete(object) | Removes the object |
Like WeakMap, WeakSet has no size and is not iterable.
Real Use Case: Tracking Visited Objects
WeakSet is ideal for marking objects that have been processed without modifying the object or leaking memory.
let processed = new WeakSet();
function processUser(user) {
if (processed.has(user)) {
console.log("Already processed:", user.name);
return;
}
// Do work here
console.log("Processing:", user.name);
processed.add(user);
}
let u = { name: "Kiran" };
processUser(u); // Processing: Kiran
processUser(u); // Already processed: Kiran
// When u is set to null, the WeakSet entry cleans itself up
Diagram: WeakSet Tracking
processUser(u) called first time:
processed.has(u) → false
→ do work, add to WeakSet
processed = WeakSet{ u }
processUser(u) called second time:
processed.has(u) → true
→ skip, print "Already processed"
WeakMap vs Map, WeakSet vs Set
| Feature | Map / Set | WeakMap / WeakSet |
|---|---|---|
| Key / Value type | Any type | Keys/members must be objects |
| Iterability | Yes (forEach, for...of) | No |
| size property | Yes | No |
| Memory management | Manual (holds objects) | Automatic (garbage collected) |
| Best for | General key-value or sets | Private data, tracking, caching |
When to Use WeakMap or WeakSet
- Attaching metadata or private data to objects without modifying them.
- Tracking which DOM elements have been set up, without keeping them in memory after removal.
- Caching results tied to objects that may be discarded.
- Any situation where you want automatic memory cleanup when objects go out of use.
Summary
WeakMap and WeakSet store object references weakly — when no other code references the object, it gets garbage collected and the weak collection entry disappears automatically. WeakMap stores key-value pairs keyed on objects. WeakSet stores unique objects. Neither supports iteration or size checking. They are the right tool when you need to associate data with objects without causing memory leaks — especially in long-running apps where objects are created and destroyed frequently.
