JavaScript WeakMap and WeakSet: Complete Guide
Learn JavaScript WeakMap and WeakSet: collections with weak references that enable garbage collection. Use cases for private data, caching, and DOM node tracking.
WeakMap and WeakSet are collections similar to Map and Set, with one critical difference: they hold weak references to their keys (for WeakMap) or values (for WeakSet). A weak reference does not prevent the garbage collector from removing the object from memory.
This means if no other part of your program holds a reference to an object used as a WeakMap key, both the key and its associated value can be garbage collected.
WeakMap
Start with the basic behavior before looking at what makes WeakMap different from Map. A WeakMap is a key-value collection where keys must be objects or non-registered symbols, and references to those keys are weak:
const wm = new WeakMap();
let user = { name: "Alex" };
wm.set(user, { lastLogin: Date.now() });
console.log(wm.get(user)); // { lastLogin: ... }
user = null; // The object is now eligible for garbage collection
// The WeakMap entry will be automatically removedWhen user is set to null, the { name: "Alex" } object has no remaining strong references. The WeakMap entry for it can be collected at the next garbage collection cycle.
WeakMap API
WeakMap has a minimal API: set(), get(), has(), and delete(). It has no size property, no iteration methods, and no clear():
const wm = new WeakMap();
const obj = {};
wm.set(obj, "metadata");
console.log(wm.get(obj)); // "metadata"
console.log(wm.has(obj)); // true
wm.delete(obj);
console.log(wm.has(obj)); // falseThere is no way to enumerate the entries of a WeakMap. This is by design: garbage collection is non-deterministic, so the contents of a WeakMap at any given moment are unpredictable.
WeakSet
A WeakSet is a collection of objects with weak references. Values must be objects, and they can be garbage collected when no other references exist:
const ws = new WeakSet();
let item1 = { id: 1 };
let item2 = { id: 2 };
ws.add(item1);
ws.add(item2);
console.log(ws.has(item1)); // true
item1 = null; // Eligible for garbage collectionLike WeakMap, WeakSet has only add(), has(), and delete(). No size, no iteration, no clear().
Why Weak References Matter
In a regular Map, as long as the Map exists, every key and value it holds is kept alive:
const map = new Map();
let obj = { data: "important" };
map.set(obj, "metadata");
obj = null; // The object is still alive because the Map holds a strong reference
// Memory is not freed until map.delete(...) or map itself is collectedIn a WeakMap, setting obj = null allows the entry to be collected. The WeakMap does not prevent garbage collection. This prevents memory leaks when objects are used as keys and later discarded.
Use Case: Private Data for Classes
WeakMap is ideal for storing private data associated with class instances:
const privateData = new WeakMap();
class User {
constructor(name, email) {
privateData.set(this, { name, email });
}
getEmail() {
return privateData.get(this).email;
}
}The WeakMap lives outside the class body, keyed by each instance (this). Any method on the class can read that instance's private data through it, but code outside the module has no way to reach the WeakMap at all:
const user = new User("Alex", "alex@example.com");
console.log(user.getEmail()); // "alex@example.com"The private data is attached to each instance but inaccessible from outside the module. When an instance is garbage collected, its private data is automatically cleaned up because the WeakMap key (the instance) is gone.
Use Case: Caching Computed Results
Cache expensive computations keyed by the input object. When the input is no longer needed, the cached result is freed:
const cache = new WeakMap();
function computeExpensive(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = { computed: obj.value * 2 };
cache.set(obj, result);
return result;
}The function checks the cache before doing any work, so calling it twice with the same object only computes once:
let input = { value: 21 };
computeExpensive(input); // Computes and caches
computeExpensive(input); // Returns from cache
input = null; // Both input and cached result can be collectedA regular Map would keep the cached result forever. WeakMap ties the cache lifetime to the input object's lifetime.
Use Case: Tracking DOM Nodes with WeakSet
Track which DOM elements have been processed without preventing their removal:
const processed = new WeakSet();
function handleClick(event) {
const button = event.target;
if (processed.has(button)) return;
processed.add(button);
// Handle first click
}When a button is removed from the DOM and no other references exist, it is garbage collected and automatically removed from the WeakSet. For more on memory management patterns, see the article on /javascript/preventing-memory-leaks-with-js-weakmaps-guide.
WeakMap vs Map: Quick Comparison
| WeakMap | Map | |
|---|---|---|
| Key types | Objects or non-registered symbols | Any type |
| Reference | Weak (allows GC) | Strong (prevents GC) |
| Iteration | Not iterable | Iterable (for...of, forEach) |
| Size | No size property | size property |
| Methods | set, get, has, delete | Full API including clear, keys, values |
Common Mistake: Trying to Use Primitives as Keys
WeakMap keys must be objects or non-registered symbols. Ordinary primitives like strings and numbers throw a TypeError, because they cannot be garbage collected the way objects can:
const wm = new WeakMap();
// Throws TypeError: Invalid value used as weak map key
// wm.set("key", "value");
// wm.set(42, "value");If you need string or number keys, use a regular Map. WeakMap is specifically for associating data with object instances (or unique symbols). For a side-by-side comparison, see the article on /javascript/map-vs-object-in-javascript-complete-guide.
Rune AI
Key Insights
- WeakMap holds weak references to its object keys, allowing garbage collection when no other references exist.
- WeakMap only accepts objects or non-registered symbols as keys; WeakSet only accepts objects as values.
- Neither WeakMap nor WeakSet is iterable or has a size property.
- Use WeakMap for private data, caching, and metadata tied to object lifetimes.
- Use WeakSet for tracking which objects have been processed without preventing their cleanup.
Frequently Asked Questions
What is the difference between Map and WeakMap?
When should I use a WeakMap?
Can I iterate over a WeakMap or WeakSet?
Conclusion
WeakMap and WeakSet solve a specific problem: associating data with objects without keeping those objects alive. Use WeakMap for private instance data and object-keyed caches. Use WeakSet for tracking object membership. Their API is deliberately minimal because the collection's contents depend on garbage collection, which is non-deterministic.
More in this topic
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.
How to Loop Through Arrays Using JS for Loops Guide
Looping through arrays is the most practical use of JavaScript for loops. Learn how to access each element by index, avoid off-by-one errors, and choose between for, for...of, and forEach.