WeakMap and WeakSet

Difficulty: Intermediate

Question

What are WeakMap and WeakSet? How do they differ from Map and Set?

Answer

WeakMap and WeakSet hold weak references to their keys/values, meaning the garbage collector can collect the referenced objects even if they still appear in the WeakMap/WeakSet.

Key differences from Map/Set: - Keys (WeakMap) or values (WeakSet) must be objects - Not iterable - no forEach, keys(), values(), or size property - Entries are automatically removed when the referenced object is garbage collected

Use cases: - WeakMap: storing private data or metadata associated with DOM nodes or class instances without preventing GC - WeakSet: tracking objects that have been processed

Code examples

WeakMap for Private Data

const _private = new WeakMap();

class Counter {
  constructor() {
    _private.set(this, { count: 0 });
  }

  increment() {
    _private.get(this).count++;
  }

  get value() {
    return _private.get(this).count;
  }
}

const c = new Counter();
c.increment();
c.increment();
console.log(c.value); // 2
console.log(c.count); // undefined - truly private

WeakMap stores private state keyed by the instance. When the instance is garbage collected, the data in the WeakMap is also collected.

WeakSet for Circular Reference Detection

function deepClone(obj, seen = new WeakSet()) {
  if (typeof obj !== 'object' || obj === null) return obj;
  if (seen.has(obj)) throw new Error('Circular reference detected');
  seen.add(obj);
  const clone = Array.isArray(obj) ? [] : {};
  for (const key of Object.keys(obj)) {
    clone[key] = deepClone(obj[key], seen);
  }
  return clone;
}

const a = { x: 1, nested: { y: 2 } };
console.log(deepClone(a));

const circular = { name: 'test' };
circular.self = circular;
try {
  deepClone(circular);
} catch (e) {
  console.log(e.message);
}

WeakSet tracks seen objects without preventing GC. Using a regular Set would hold strong references and could cause memory leaks.

Key points

Concepts covered

WeakMap, WeakSet, Garbage Collection, Memory