Skip to content
Home JavaScript WeakMap and WeakSet in JavaScript

WeakMap and WeakSet in JavaScript

Where developers are forged. · Structured learning · Free forever.
📍 Part of: Advanced JS → Topic 12 of 27
JavaScript WeakMap and WeakSet — what makes them 'weak', how garbage collection works differently, use cases like private data and DOM node caches, and limitations.
🔥 Advanced — solid JavaScript foundation required
In this tutorial, you'll learn
JavaScript WeakMap and WeakSet — what makes them 'weak', how garbage collection works differently, use cases like private data and DOM node caches, and limitations.
  • WeakMap and WeakSet hold weak references — objects can be garbage collected even when held as keys.
  • Keys must be objects (or registered symbols in WeakMap) — primitives are not allowed.
  • Neither is iterable — no .forEach(), no .keys(), no .size. This is intentional.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
Quick Answer

WeakMap and WeakSet hold weak references to their keys/values — if no other reference to the object exists, it can be garbage collected even if it is in a WeakMap or WeakSet. This makes them ideal for caching data associated with objects without preventing those objects from being collected. Limitation: they are not iterable.

WeakMap — Object-keyed Private Data

Example · JAVASCRIPT
123456789101112131415161718192021222324
const privateData = new WeakMap();

class Person {
    constructor(name, age) {
        // Store private data keyed by this instance
        privateData.set(this, { age, secretCode: Math.random() });
        this.name = name;  // public
    }

    getAge() {
        return privateData.get(this).age;  // private data not on the object
    }

    greet() {
        return `Hi, I'm ${this.name}, age ${this.getAge()}`;
    }
}

const alice = new Person('Alice', 30);
console.log(alice.greet());      // Hi, I'm Alice, age 30
console.log(alice.age);          // undefined — not a public property
console.log(alice.secretCode);   // undefined — truly private

// When alice goes out of scope and is GC'd, privateData entry is also collected
▶ Output
Hi, I'm Alice, age 30
undefined
undefined

WeakMap vs Map for Caching

Example · JAVASCRIPT
123456789101112131415161718192021222324252627
// Problem: regular Map prevents garbage collection of DOM nodes
const cache = new Map();

function processElement(el) {
    if (cache.has(el)) return cache.get(el);
    const result = expensiveComputation(el);
    cache.set(el, result);
    return result;
}
// If el is removed from the DOM, cache still holds a reference → memory leak

// Solution: WeakMap — entry removed when el is GC'd
const weakCache = new WeakMap();

function processElementSafe(el) {
    if (weakCache.has(el)) return weakCache.get(el);
    const result = { processed: true, timestamp: Date.now() };
    weakCache.set(el, result);
    return result;
}

// Keys must be objects — not primitives
const obj = {};
weakCache.set(obj, 'data');   // OK
// weakCache.set('string', 'data');  // TypeError: Invalid value used as weak map key

function expensiveComputation(el) { return { computed: true }; }
▶ Output
WeakMap entries GC'd automatically when key objects are no longer reachable

WeakSet — Tracking Object Membership

Example · JAVASCRIPT
123456789101112131415161718192021
const visited = new WeakSet();

function processNode(node) {
    if (visited.has(node)) {
        console.log('Already processed, skipping');
        return;
    }
    visited.add(node);
    console.log('Processing node:', node.id);
    // process...
}

const nodeA = { id: 'a', data: 'hello' };
const nodeB = { id: 'b', data: 'world' };

processNode(nodeA);  // Processing node: a
processNode(nodeA);  // Already processed, skipping
processNode(nodeB);  // Processing node: b

// WeakSet only has: add(), has(), delete()
// No size, no iteration — by design (GC timing is unpredictable)
▶ Output
Processing node: a
Already processed, skipping
Processing node: b

🎯 Key Takeaways

  • WeakMap and WeakSet hold weak references — objects can be garbage collected even when held as keys.
  • Keys must be objects (or registered symbols in WeakMap) — primitives are not allowed.
  • Neither is iterable — no .forEach(), no .keys(), no .size. This is intentional.
  • Primary use case: caching metadata about objects without preventing their collection.
  • WeakRef and FinalizationRegistry (ES2021) are the more explicit tools if you need to react to GC.

Interview Questions on This Topic

  • QWhat is the difference between a Map and a WeakMap in JavaScript?
  • QWhy are WeakMap and WeakSet not iterable?
  • QGive a practical use case for WeakMap.

Frequently Asked Questions

When should I use WeakMap over Map?

Use WeakMap when the keys are DOM nodes or objects whose lifetime you do not control, and you want the associated data to be automatically cleaned up when the key is collected. If you need to iterate entries, check size, or use primitive keys, use Map.

Why can't WeakMap and WeakSet be iterated?

Because the garbage collector can remove entries at any time — there is no guaranteed order or set of entries at any given moment. Exposing iteration would either force the GC to not collect entries (defeating the purpose) or produce inconsistent results.

🔥
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousSymbol and BigInt in JavaScriptNext →Generators in JavaScript
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged