Explorer
JavaScript

WeakMap and WeakSet

JavaScript Theory & Concepts

WeakMap and WeakSet in JavaScript

Garbage-collection-friendly collections, memory leak prevention, and private data patterns.

📖 The Story & Real-World Analogy

The Museum Visitor Coat Check Tag

"When a visitor enters an art museum, the front desk pins a barcode tag on their coat (an object key in a `WeakMap`) associated with their locker data. As long as the visitor is in the building, you can scan their coat and see their locker. But the moment the visitor leaves the building and goes home (no other references to the visitor object exist in memory), the coat check entry automatically dissolves and is swept away by the museum cleaners (Garbage Collector). No leftover paper tags or locker clutter remain!"

Standard `Map` and `Set` maintain strong references to keys and values, preventing garbage collection even if objects are discarded elsewhere. `WeakMap` and `WeakSet` hold "weak" references that do not block the GC.

⚙️ How It Works Under The Hood (Step-by-Step)
1

Weak References to Keys

In a `WeakMap`, keys MUST be objects (or non-registered symbols). If an object key has no other references in memory, it and its associated value are automatically garbage collected.

2

Non-Enumerable by Design

`WeakMap` and `WeakSet` have NO `.size` property, NO `.keys()`, and NO `forEach()` iterator. Because garbage collection runs non-deterministically, the collection size cannot be observed.

3

Private Instance State

Store private properties in a module-scoped `WeakMap` keyed by `this`. When an instance is dereferenced, its private state is automatically garbage collected.

4

DOM Metadata and Caching

Ideal for attaching event count or listener metadata to DOM nodes. When the DOM element is removed from the tree, its metadata is collected without manual cleanup.

💻 Interactive Code Walkthrough

Attaching metadata to DOM nodes and encapsulating private state safely:

JAVASCRIPT
// Safe metadata attachment without memory leaks
const clickCountTracker = new WeakMap();

function recordButtonClick(buttonElement) {
  const currentClicks = clickCountTracker.get(buttonElement) || 0;
  clickCountTracker.set(buttonElement, currentClicks + 1);
  return clickCountTracker.get(buttonElement);
}

// Simulating DOM node lifecycle
let fakeButton = { id: "submit-btn" };
console.log("Click 1:", recordButtonClick(fakeButton));
console.log("Click 2:", recordButtonClick(fakeButton));

// When fakeButton is unmounted from DOM and dereferenced:
fakeButton = null; 
// At this point, clickCountTracker will automatically release the entry during GC!
Console Output:
CODE
Click 1: 1
Click 2: 2
⚠️ Common Pitfalls & Interview Traps
Trap
Passing Primitive Keys to WeakMap

The Risk: `weakMap.set("user_id", data)` throws `TypeError: Invalid value used as weak map key` because primitives cannot be weakly referenced.

The Fix: Use standard `Map` for primitive keys, or ensure keys are object references.

⚡ 30-Second Quick Revision Cheat Sheet (TL;DR)
  • ✓ Keys in `WeakMap` and values in `WeakSet` MUST be objects (or registered symbols).
  • ✓ Does NOT prevent Garbage Collection: entries are automatically swept when key object is unreferenced.
  • ✓ Non-iterable: No `.size`, `.keys()`, `.entries()`, or `.forEach()`.
  • ✓ Only provides: `.get()`, `.set()`, `.has()`, `.delete()` (or `.add()`, `.has()`, `.delete()`).
  • ✓ Perfect for DOM node metadata, caching, and private instance fields.

Finished this lesson?

Mark this chapter complete to update your learning streak and unlock the next lesson.