DEV Community

Cover image for What are WeakMaps in JS?
Syed Ammar
Syed Ammar

Posted on

What are WeakMaps in JS?

A WeakMap in JavaScript is a collection of key-value pairs where the keys are required to be objects, and the references to these keys are "weak." This means that if there are no other references to a key object, it can be garbage-collected, even if it is still in the WeakMap.


Key Features

  1. Keys must be objects:

    • Primitive values (like numbers, strings, or booleans) cannot be used as keys.
    • Only objects and functions are allowed as keys.
  2. Weak references:

    • The key objects in a WeakMap are held weakly.
    • If no other references exist to a key, the key-value pair will be automatically removed from the WeakMap.
  3. Not iterable:

    • WeakMap does not have methods like forEach, and it cannot be looped through using constructs like for...of or Object.keys().
    • This is because the garbage collection process makes it impossible to reliably list all entries.
  4. Useful for private data:

    • WeakMap is often used to associate private data with objects without exposing it.

Syntax

const weakMap = new WeakMap();
Enter fullscreen mode Exit fullscreen mode

Methods

Method Description
weakMap.set(key, value) Adds a new key-value pair or updates an existing key.
weakMap.get(key) Retrieves the value associated with the key.
weakMap.has(key) Checks if the key exists in the WeakMap.
weakMap.delete(key) Removes the key-value pair associated with the key.

Examples

Basic Usage

const weakMap = new WeakMap();

const obj1 = { name: "Alice" };
const obj2 = { name: "Bob" };

// Adding key-value pairs
weakMap.set(obj1, "Data for Alice");
weakMap.set(obj2, "Data for Bob");

// Accessing values
console.log(weakMap.get(obj1)); // Output: "Data for Alice"

// Checking existence
console.log(weakMap.has(obj2)); // Output: true

// Removing a key-value pair
weakMap.delete(obj2);
console.log(weakMap.has(obj2)); // Output: false
Enter fullscreen mode Exit fullscreen mode

Garbage Collection

let obj = { key: "value" };
const weakMap = new WeakMap();
weakMap.set(obj, "Some data");

// Remove all references to `obj`
obj = null;

// The `WeakMap` entry for `obj` is automatically removed by garbage collection.
Enter fullscreen mode Exit fullscreen mode

Use Cases

  1. Private Data Storage:
    • Associate private data with an object, ensuring it is not exposed or accessible elsewhere.
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()); // Output: "Alice"
Enter fullscreen mode Exit fullscreen mode
  1. DOM Node Metadata:
    • Store metadata related to DOM elements without preventing garbage collection.
const metadata = new WeakMap();

function trackElement(element) {
    metadata.set(element, { clicks: 0 });
}

function incrementClicks(element) {
    const data = metadata.get(element);
    if (data) {
        data.clicks++;
    }
}

const button = document.createElement("button");
trackElement(button);
incrementClicks(button);
console.log(metadata.get(button)); // Output: { clicks: 1 }
Enter fullscreen mode Exit fullscreen mode

Advantages

  • Memory Efficiency: Automatic removal of unreferenced keys helps manage memory effectively.
  • Encapsulation: Provides a way to store data privately and securely.
  • No Memory Leaks: Prevents accidental memory leaks by allowing garbage collection of keys.

Limitations

  1. Non-iterable:
    • Cannot list all keys or values.
  2. Only Object Keys:
    • Does not support primitive keys.
  3. Limited Use Cases:
    • Not suitable for scenarios requiring enumeration or full access to stored data.

In summary, WeakMap is a specialized collection designed for scenarios where weak references and private associations are required.

Difference between Map and WeakMap

The primary difference between Map and WeakMap in JavaScript lies in their handling of keys, garbage collection, and functionality. Here’s a detailed comparison:


Key Differences

Feature Map WeakMap
Key Types Keys can be any type: objects, primitives. Keys must be objects.
Garbage Collection Does not rely on garbage collection; keys persist. Keys are held weakly and can be garbage-collected.
Iteration Iterable (can use for...of, forEach, etc.). Not iterable (cannot list keys or values).
Size Property Has a size property to get the number of entries. No size property available.
Use Case General-purpose key-value storage. Specialized for associating metadata or private data with objects.
Performance Slightly slower due to strong key references. Faster for memory-sensitive operations due to weak references.

Feature Comparison

1. Key Types

  • Map: Accepts both objects and primitive types (like strings, numbers, booleans) as keys.
  • WeakMap: Only accepts objects as keys. Primitives are not allowed.
const map = new Map();
map.set(1, "value"); // Allowed
map.set("key", "value"); // Allowed
map.set({}, "value"); // Allowed

const weakMap = new WeakMap();
weakMap.set({}, "value"); // Allowed
weakMap.set(1, "value"); // TypeError: Invalid value used as weak map key
Enter fullscreen mode Exit fullscreen mode

2. Garbage Collection

  • Map: Retains a strong reference to the key, preventing it from being garbage-collected as long as it exists in the map.
  • WeakMap: Holds a weak reference to the key, allowing it to be garbage-collected if there are no other references.
let key = { id: 1 };
const map = new Map();
const weakMap = new WeakMap();

map.set(key, "Map Value");
weakMap.set(key, "WeakMap Value");

key = null; // Remove reference to the object

// In Map, the entry still exists
console.log(map); // Map(1) { { id: 1 } => 'Map Value' }

// In WeakMap, the entry is removed by garbage collection
console.log(weakMap); // WeakMap {}
Enter fullscreen mode Exit fullscreen mode

3. Iteration

  • Map: Iterable. You can use for...of, .keys(), .values(), .entries(), or .forEach() to iterate over its contents.
  • WeakMap: Not iterable. There are no methods to retrieve all keys, values, or entries.
const map = new Map();
map.set("a", 1);
map.set("b", 2);

for (const [key, value] of map) {
    console.log(key, value);
}
// Output:
// a 1
// b 2

const weakMap = new WeakMap();
weakMap.set({}, "value");
// Cannot iterate over WeakMap
Enter fullscreen mode Exit fullscreen mode

4. Size Property

  • Map: Provides a size property that returns the number of entries.
  • WeakMap: Does not have a size property since it is not iterable and entries are weakly referenced.
const map = new Map();
map.set("a", 1);
console.log(map.size); // Output: 1

const weakMap = new WeakMap();
weakMap.set({}, "value");
console.log(weakMap.size); // Undefined
Enter fullscreen mode Exit fullscreen mode

Use Cases

When to Use Map

  • General-purpose key-value storage.
  • Scenarios requiring enumeration or iteration of keys and values.
  • Keys may be primitives or objects.

Example:

const map = new Map();
map.set("id", 123);
map.set("name", "Alice");

console.log(map.get("id")); // Output: 123
console.log([...map.keys()]); // Output: ['id', 'name']
Enter fullscreen mode Exit fullscreen mode

When to Use WeakMap

  • When you need to associate metadata or private data with objects without preventing garbage collection.
  • Ideal for cases where the lifetime of the key should dictate the lifetime of the associated value.

Example:

const weakMap = new WeakMap();

class User {
    constructor(name) {
        weakMap.set(this, { privateData: `Data for ${name}` });
    }

    getPrivateData() {
        return weakMap.get(this).privateData;
    }
}

const user = new User("Alice");
console.log(user.getPrivateData()); // Output: Data for Alice
Enter fullscreen mode Exit fullscreen mode

Summary

Feature Map WeakMap
Flexibility General-purpose, flexible. Specialized, limited use case.
Performance Persistent key references. Memory-efficient with weak references.
Suitability Iteration and long-term storage. Private data and ephemeral relationships.

Top comments (0)