Imagine a storage locker that vanishes the moment you no longer need its contents.

That’s the magic of WeakMap and WeakSet — two powerful data structures introduced in ES6 (ECMAScript 2015). They address challenges in memory management and efficient data handling, offering solutions for developers who want cleaner, smarter code.

In this article, we’ll explore:

  • Why WeakMap and WeakSet were introduced.
  • Their unique characteristics and differences.
  • Real-world use cases, complete with examples like caching, private data, and metadata storage.
  • How modern frameworks like React and Vue use these structures.

Let’s dive in!


History and Motivation Behind WeakMap and WeakSet

Before ES6, developers often grappled with memory leaks caused by improper references to objects. For instance, if a Map held a reference to an object, that object couldn’t be garbage-collected—even if it was no longer needed elsewhere.

To address this problem, WeakMap and WeakSet were introduced:

  • They store weakly-held object references, meaning unused objects can be garbage-collected.
  • Ideal for scenarios where temporary or private data storage is essential.

Understanding WeakMap and WeakSet

WeakMap

A WeakMap is a collection of key-value pairs where:

  • Keys must be objects.
  • Values can be of any type.
  • Keys are weakly held, meaning they don’t prevent garbage collection.

Key Characteristics:

  • Not iterable (e.g., no forEach or keys() methods).
  • Keys are always objects (no primitives like strings or numbers).
  • Values are only accessible if the corresponding key exists.

Syntax:

const weakMap = new WeakMap();
weakMap.set(keyObject, value);

const value = weakMap.get(keyObject);
weakMap.delete(keyObject);

WeakSet

A WeakSet is a collection of unique object values where:

  • Values are weakly held, ensuring garbage collection when objects are no longer needed.
  • Duplicate values are ignored.

Key Characteristics:

  • Not iterable.
  • Only objects can be added as values.

Syntax:

const weakSet = new WeakSet();

weakSet.add(objectValue);
weakSet.has(objectValue);
weakSet.delete(objectValue);

Real-World Use Cases

Storing Private Data

WeakMap is perfect for storing private data tied to specific objects without exposing it to the outside world.

Example:

const privateData = new WeakMap();

class User {
  constructor(name) {
    privateData.set(this, { name });
  }

  getName() {
    return privateData.get(this).name;
  }
}

const user = new User("Alice");
console.log(user.getName()); // Alice

Here, privateData ensures the name property remains inaccessible outside the User class.


Avoiding Memory Leaks

WeakMap ensures objects are garbage-collected when no longer referenced elsewhere, preventing memory leaks.

Example:

const cache = new WeakMap();

function processImage(image) {
  if (!cache.has(image)) {
    const processed = `Processed ${image}`;
    cache.set(image, processed);
  }
  return cache.get(image);
}

let img = { src: "image.jpg" };
console.log(processImage(img)); // Processed image.jpg
img = null; // The image object is garbage-collected.

Caching with WeakMap

WeakMap’s weakly-held keys make it ideal for implementing object-specific caches.

Example:

class Cache {
  constructor() {
    this.cache = new WeakMap();
  }

  add(key, value) {
    this.cache.set(key, value);
  }

  get(key) {
    return this.cache.get(key);
  }
}

const dataCache = new Cache();
let user = { id: 1 };
dataCache.add(user, "User Data");

console.log(dataCache.get(user)); // User Data
user = null; // Cached user is garbage-collected.

In this example, the user object and its associated cache entry are garbage-collected once the object reference is cleared.


Storing Metadata with WeakMap

WeakMap lets you associate metadata with objects without altering their structure.

Example:

const metadata = new WeakMap();

function annotate(obj, info) {
  metadata.set(obj, info);
}

function getMetadata(obj) {
  return metadata.get(obj);
}

const file = { name: "file1.txt" };
annotate(file, { owner: "Alice", size: "15KB" });

console.log(getMetadata(file)); // { owner: "Alice", size: "15KB" }

The metadata is weakly associated with the object, ensuring it is garbage-collected with the object.


Tracking DOM Elements

WeakSet can track DOM elements without preventing their garbage collection.

Example:

const visitedNodes = new WeakSet();

function visitNode(node) {
  if (!visitedNodes.has(node)) {
    visitedNodes.add(node);

    console.log(`Visiting ${node.id}`);
  }
}

const div = document.createElement("div");

div.id = "test";

visitNode(div); // Visiting test

Framework Use: React and Vue

Modern frameworks leverage WeakMap and WeakSet for performance optimization and reactive state management.

React

const fiberMap = new WeakMap();

function associateFiber(element, fiber) {
  fiberMap.set(element, fiber);
}

function getFiber(element) {
  return fiberMap.get(element);
}

const element = { type: "div" };
const fiber = { id: "fiber_1" };

associateFiber(element, fiber);

console.log(getFiber(element)); // { id: "fiber_1" }

Vue

const reactivityMap = new WeakMap();

function reactive(obj) {
  const proxy = new Proxy(obj, {
    get(target, key) {
      console.log(`Accessed ${key}`);
      return target[key];
    },
    set(target, key, value) {
      target[key] = value;
      console.log(`Updated ${key} to ${value}`);
      return true;
    },
  });
  
  reactivityMap.set(obj, proxy);
  
  return proxy;
}

const state = { count: 0 };
const reactiveState = reactive(state);

reactiveState.count++;
// Accessed count
// Updated count to 1

Key Differences Between WeakMap and WeakSet

FeatureWeakMapWeakSet
Data TypeKey-Value pairsUnique object values
KeysOnly objectsNot applicable
ValuesAnyOnly objects
IterabilityNoNo
Garbage CollectionWeakly held keysWeakly held values


Conclusion

WeakMap and WeakSet may not replace traditional Maps or Sets, but their unique ability to manage memory and handle temporary or private data makes them indispensable tools for modern JavaScript development. Whether you’re building a caching system or developing a cutting-edge framework, these structures can help you write cleaner, more efficient code.