🗝️ WeakMap & WeakSet: The Magical Self-Cleaning Storage
🎭 The Story of the Forgetful Librarian
Imagine a library with a magical librarian who has a special power: she can link secret notes to books. But here’s the twist—when a book leaves the library forever, the note attached to it vanishes automatically. No cleanup needed!
This is exactly what WeakMap and WeakSet do in JavaScript. They hold onto things weakly—meaning when nobody else cares about an object, these collections let go too.
📦 What is a WeakMap?
A WeakMap is like a secret drawer where:
- You can only use objects as keys (not strings or numbers!)
- When the key object is gone, the whole entry disappears automatically
- You can’t peek inside to see all entries (no listing allowed!)
🧒 Simple Explanation
Think of putting a sticky note on your toy:
- The sticky note (value) is attached to your toy (key)
- If you throw away the toy, the sticky note goes too
- You can only find the note if you have the toy!
✨ Creating a WeakMap
// Create an empty WeakMap
const secretNotes = new WeakMap();
// Objects to use as keys
const toy1 = { name: "Teddy Bear" };
const toy2 = { name: "Robot" };
📝 WeakMap Methods
WeakMaps have only 4 simple methods:
// SET - Attach a value to an object
secretNotes.set(toy1, "This is my favorite!");
// GET - Read the attached value
secretNotes.get(toy1);
// Returns: "This is my favorite!"
// HAS - Check if object has a note
secretNotes.has(toy1); // true
secretNotes.has(toy2); // false
// DELETE - Remove the note
secretNotes.delete(toy1);
🚫 What You CAN’T Do
// ❌ Can't use strings or numbers as keys
secretNotes.set("hello", "value");
// TypeError!
// ❌ Can't see how many entries
secretNotes.size; // undefined
// ❌ Can't loop through entries
// No forEach, no keys(), no values()
🎯 WeakMap Use Cases
1. 🔐 Private Data for Objects
Hide secret information that only you can access!
const privateData = new WeakMap();
class BankAccount {
constructor(name, balance) {
// Hide the balance secretly!
privateData.set(this, {
balance: balance
});
this.name = name;
}
getBalance() {
return privateData.get(this).balance;
}
}
const myAccount = new BankAccount("Alex", 100);
myAccount.getBalance(); // 100
// But nobody can see privateData directly!
2. 📊 Caching (Remembering Results)
Store computed results without memory leaks:
const cache = new WeakMap();
function getHeavyData(user) {
// Already calculated? Return saved result!
if (cache.has(user)) {
return cache.get(user);
}
// Calculate and save
const result = /* expensive work */;
cache.set(user, result);
return result;
}
// When user is deleted, cache cleans itself!
3. 🎨 Tracking DOM Elements
Attach data to webpage elements safely:
const elementData = new WeakMap();
const button = document.querySelector("#myBtn");
elementData.set(button, {
clickCount: 0
});
// When button is removed from page,
// the data vanishes automatically!
🎪 What is a WeakSet?
A WeakSet is even simpler! It’s like a VIP guest list where:
- Only objects can be members
- Each object can only appear once
- When an object is gone, it leaves the list automatically
🧒 Simple Explanation
Imagine a magical stamp on toys:
- You stamp a toy = it’s in the set
- Throw away the toy = stamp disappears
- You can’t see all stamped toys at once!
✨ Creating a WeakSet
const stampedToys = new WeakSet();
const toy1 = { name: "Doll" };
const toy2 = { name: "Car" };
📝 WeakSet Methods
Only 3 methods (even simpler!):
// ADD - Stamp an object
stampedToys.add(toy1);
stampedToys.add(toy2);
// HAS - Check if stamped
stampedToys.has(toy1); // true
stampedToys.has(toy2); // true
// DELETE - Remove stamp
stampedToys.delete(toy1);
stampedToys.has(toy1); // false
🎯 WeakSet Use Case: Tracking Visited Objects
const visited = new WeakSet();
function processOnce(obj) {
if (visited.has(obj)) {
return "Already processed!";
}
visited.add(obj);
// Do the work...
return "Processing complete!";
}
const user = { name: "Sam" };
processOnce(user); // "Processing complete!"
processOnce(user); // "Already processed!"
🔄 WeakMap vs WeakSet vs Regular
graph TD A["Choose Your Collection"] --> B{Need key-value pairs?} B -->|Yes| C{Keys must be objects?} B -->|No| D{Only objects?} C -->|Yes & auto-cleanup| E["✅ WeakMap"] C -->|No| F["Use Map"] D -->|Yes & auto-cleanup| G["✅ WeakSet"] D -->|No| H["Use Set"]
| Feature | Map | WeakMap | Set | WeakSet |
|---|---|---|---|---|
| Key types | Any | Objects only | - | - |
| Value types | Any | Any | Objects | Objects only |
| Size property | ✅ | ❌ | ✅ | ❌ |
| Iterable | ✅ | ❌ | ✅ | ❌ |
| Auto-cleanup | ❌ | ✅ | ❌ | ✅ |
🧹 The Magic of Garbage Collection
Here’s the superpower:
let user = { name: "Alex" };
const data = new WeakMap();
data.set(user, "secret");
// User exists, data exists
data.get(user); // "secret"
// Remove the only reference
user = null;
// 🪄 Magic happens!
// JavaScript garbage collector removes user
// WeakMap entry vanishes automatically!
// No memory leak!
🎓 Quick Recap
WeakMap
- 🔑 Keys must be objects
- 💾 Stores key-value pairs
- 🧹 Auto-cleans when key is gone
- 🔒 Great for private data & caching
WeakSet
- 📦 Only stores objects
- ✓ Just tracks “is it in the set?”
- 🧹 Auto-cleans when object is gone
- 📝 Great for marking/tracking objects
💡 Golden Rules
- Use WeakMap when you need to attach data to objects that might disappear
- Use WeakSet when you just need to mark objects without storing extra data
- Can’t iterate over weak collections (that’s the trade-off for auto-cleanup!)
- No size property — you can’t count entries
🚀 You Did It!
You now understand JavaScript’s self-cleaning storage!
WeakMap and WeakSet are like magical containers that never cause memory leaks. They hold things gently—and let go when it’s time.
Use them when you want to attach information to objects without worrying about cleanup. JavaScript will handle the rest! 🎉
