JavaScript - JavaScript WeakMap and WeakSet
1. Introduction
JavaScript provides several built-in data structures for storing and managing collections of values. The most commonly used collections are arrays, objects, Map, and Set. In addition to these, JavaScript offers two specialized collections called WeakMap and WeakSet.
WeakMap and WeakSet are useful when you want to associate information with objects without necessarily keeping those objects alive in memory.
They are particularly helpful in situations such as:
-
Storing private or internal data associated with objects.
-
Caching information about objects.
-
Tracking objects that have already been processed.
-
Managing metadata without manually removing it when objects are no longer needed.
-
Working with memory-sensitive applications.
The main difference between these collections and ordinary Map or Set is their relationship with garbage collection.
2. What is WeakMap?
A WeakMap is a JavaScript collection that stores key-value pairs, where the keys must be objects or non-registered symbols.
Unlike a normal Map, a WeakMap does not keep an object key alive merely because the key is stored in the collection.
Basic syntax
JavaScript
const weakMap = new WeakMap();
You can add key-value pairs using the set() method.
JavaScript
const user = {
name: "Rahul"
};
const userDetails = {
role: "Developer",
experience: 3
};
const weakMap = new WeakMap();
weakMap.set(user, userDetails);
console.log(weakMap.get(user));
Output:
{ role: "Developer", experience: 3 }
Explanation
In this example:
-
useris an object. -
userDetailscontains additional information. -
weakMapstoresuseras the key. -
userDetailsis stored as the corresponding value. -
get(user)retrieves the value associated with that object.
The object itself is used as the key, rather than a string such as "user".
3. Why is WeakMap called "Weak"?
The term "weak" refers to how the collection interacts with garbage collection.
JavaScript engines automatically remove objects from memory when they are no longer reachable through strong references. This process is called garbage collection.
A WeakMap does not create a strong reference to an object key.
Consider the following example:
JavaScript
let user = {
name: "Anita"
};
const weakMap = new WeakMap();
weakMap.set(user, {
role: "Manager"
});
user = null;
After user = null, there is no longer a strong reference to the original object from the user variable.
If the WeakMap is the only remaining reference involving that object, the object can become eligible for garbage collection.
The associated entry may then disappear as part of garbage collection.
Important point
You cannot force garbage collection using ordinary JavaScript code, and you cannot observe the exact moment when a WeakMap entry is removed.
The purpose of WeakMap is to allow the garbage collector to reclaim objects when they are no longer otherwise reachable.
4. WeakMap Methods
WeakMap has a small set of methods.
|
Method
|
Purpose
|
| --- | --- |
|
set(key, value)
|
Adds or updates an entry
|
|
get(key)
|
Retrieves the value
|
|
has(key)
|
Checks whether a key exists
|
|
delete(key)
|
Removes an entry
|
WeakMap does not provide the usual collection-wide iteration methods such as keys(), values(), or entries().
4.1 set()
The set() method adds a key-value pair.
JavaScript
const weakMap = new WeakMap();
const employee = {
id: 101
};
weakMap.set(employee, "Software Engineer");
console.log(weakMap.get(employee));
Output:
Software Engineer
If the same key is used again, its value is replaced.
JavaScript
weakMap.set(employee, "Senior Software Engineer");
console.log(weakMap.get(employee));
Output:
Senior Software Engineer
4.2 get()
The get() method retrieves the value associated with a key.
JavaScript
const employee = {
name: "Priya"
};
const weakMap = new WeakMap();
weakMap.set(employee, {
department: "IT"
});
console.log(weakMap.get(employee));
Output:
{ department: "IT" }
If the key does not exist, get() returns undefined.
JavaScript
const anotherEmployee = {
name: "Kiran"
};
console.log(weakMap.get(anotherEmployee));
Output:
undefined
4.3 has()
The has() method checks whether a key exists.
JavaScript
const employee = {
name: "Priya"
};
const weakMap = new WeakMap();
weakMap.set(employee, "Developer");
console.log(weakMap.has(employee));
Output:
true
Checking a different object with the same properties returns false.
JavaScript
const anotherEmployee = {
name: "Priya"
};
console.log(weakMap.has(anotherEmployee));
Output:
false
This happens because objects are compared by identity, not by whether their properties contain the same values.
4.4 delete()
The delete() method removes an entry from the WeakMap.
JavaScript
const employee = {
name: "Priya"
};
const weakMap = new WeakMap();
weakMap.set(employee, "Developer");
console.log(weakMap.has(employee));
weakMap.delete(employee);
console.log(weakMap.has(employee));
Output:
true
false
5. WeakMap Keys Must Be Objects
WeakMap keys must be objects or non-registered symbols.
Valid keys include:
-
Ordinary objects.
-
Arrays.
-
Functions.
-
Dates.
-
Other supported object values.
-
Non-registered symbols.
Valid example
JavaScript
const weakMap = new WeakMap();
const objectKey = {};
const arrayKey = [];
const functionKey = function () {};
weakMap.set(objectKey, "Object data");
weakMap.set(arrayKey, "Array data");
weakMap.set(functionKey, "Function data");
console.log(weakMap.get(objectKey));
console.log(weakMap.get(arrayKey));
console.log(weakMap.get(functionKey));
Output:
Object data
Array data
Function data
Invalid example
JavaScript
const weakMap = new WeakMap();
weakMap.set("name", "Rahul");
This throws a TypeError because "name" is a string, not a valid WeakMap key.
The same restriction applies to numbers and booleans.
JavaScript
weakMap.set(10, "Number data");
This is also invalid.
Why object keys?
WeakMap is designed to associate information with object identities. This allows the lifetime of the key object to determine whether its entry can eventually be reclaimed.
6. WeakMap vs Map
Both Map and WeakMap store key-value pairs, but their behavior differs.
|
Feature
|
Map
|
WeakMap
|
| --- | --- | --- |
|
Stores key-value pairs
|
Yes
|
Yes
|
|
Object keys
|
Yes
|
Yes
|
|
Primitive keys
|
Yes
|
No
|
|
size property
|
Yes
|
No
|
|
keys() method
|
Yes
|
No
|
|
values() method
|
Yes
|
No
|
|
entries() method
|
Yes
|
No
|
|
forEach() method
|
Yes
|
No
|
|
clear() method
|
Yes
|
No
|
|
Weak references to object keys
|
No
|
Yes
|
|
Suitable for object-associated metadata
|
Yes
|
Yes
|
Map example
JavaScript
const map = new Map();
const user = {
name: "Rahul"
};
map.set(user, "Developer");
console.log(map.size);
Output:
1
A Map keeps its key strongly reachable through the collection.
WeakMap example
JavaScript
const weakMap = new WeakMap();
const user = {
name: "Rahul"
};
weakMap.set(user, "Developer");
console.log(weakMap.has(user));
Output:
true
WeakMap does not expose a size property.
JavaScript
console.log(weakMap.size);
Output:
undefined
Which should you use?
Use Map when you need to:
-
Store and iterate over all entries.
-
Count entries.
-
Use strings or numbers as keys.
-
Maintain a collection of values for as long as the Map exists.
Use WeakMap when you need to:
-
Associate data with objects.
-
Avoid keeping object keys alive solely through the collection.
-
Store object-specific metadata or caches.
7. Practical Example: Private Data Using WeakMap
Before JavaScript introduced modern private class fields, WeakMap was a common technique for storing data that should not be directly exposed as a public property.
Example
JavaScript
const privateData = new WeakMap();
class Employee {
constructor(name, salary) {
privateData.set(this, {
name: name,
salary: salary
});
}
getSalary() {
return privateData.get(this).salary;
}
getName() {
return privateData.get(this).name;
}
}
const employee = new Employee("Rahul", 50000);
console.log(employee.getName());
console.log(employee.getSalary());
Output:
Rahul
50000
Explanation
-
privateDatais a WeakMap. -
Every Employee instance is used as a key.
-
The employee's name and salary are stored in the WeakMap.
-
The class methods retrieve the data using
this. -
The data is not stored as ordinary public properties on the employee object.
For example:
JavaScript
console.log(employee.salary);
Output:
undefined
This is because the salary is stored in the WeakMap rather than directly on the object.
Important note
This pattern hides data from ordinary property access, but code that has access to the WeakMap can still access the stored information. Modern JavaScript private fields (#salary) are another option for class-private state.
8. Practical Example: Caching Object Information
WeakMap can be used to store computed information associated with objects.
Suppose an application needs to calculate a result for an object. Recalculating the same result repeatedly may be inefficient.
A WeakMap can cache the result.
JavaScript
const cache = new WeakMap();
function calculateArea(rectangle) {
if (cache.has(rectangle)) {
return cache.get(rectangle);
}
const area = rectangle.width * rectangle.height;
cache.set(rectangle, area);
return area;
}
const rectangle = {
width: 10,
height: 5
};
console.log(calculateArea(rectangle));
console.log(calculateArea(rectangle));
Output:
50
50
Explanation
During the first call:
-
The rectangle is not in the cache.
-
The area is calculated.
-
The result is stored in the WeakMap.
During the second call:
-
The rectangle is already in the cache.
-
The stored result is returned.
Why WeakMap is useful here
If a rectangle object is no longer used elsewhere, its cached entry can become eligible for garbage collection along with the object.
This avoids requiring an explicit cache cleanup for every discarded object.
Limitation
WeakMap is not automatically aware of changes to object properties.
JavaScript
rectangle.width = 20;
console.log(calculateArea(rectangle));
This may return the old cached result, 50, because the cache was not invalidated.
If the object can change, the program must invalidate or update the cached value.
9. What is WeakSet?
A WeakSet is a collection that stores objects or non-registered symbols without creating strong references to those values.
Unlike WeakMap, it stores only values, not key-value pairs.
Basic syntax
JavaScript
const weakSet = new WeakSet();
Example
JavaScript
const weakSet = new WeakSet();
const user1 = {
name: "Rahul"
};
const user2 = {
name: "Priya"
};
weakSet.add(user1);
weakSet.add(user2);
console.log(weakSet.has(user1));
console.log(weakSet.has(user2));
Output:
true
true
Explanation
-
user1is added to the WeakSet. -
user2is added to the WeakSet. -
has()checks whether the objects are present. -
WeakSet does not store additional values for these objects.
10. WeakSet Methods
WeakSet provides three main methods.
|
Method
|
Purpose
|
| --- | --- |
|
add(value)
|
Adds an object or valid symbol
|
|
has(value)
|
Checks whether a value exists
|
|
delete(value)
|
Removes a value
|
10.1 add()
JavaScript
const weakSet = new WeakSet();
const product = {
id: 101,
name: "Laptop"
};
weakSet.add(product);
console.log(weakSet.has(product));
Output:
true
Adding the same object again does not create a duplicate.
JavaScript
weakSet.add(product);
weakSet.add(product);
console.log(weakSet.has(product));
Output:
true
10.2 has()
JavaScript
const weakSet = new WeakSet();
const documentObject = {};
weakSet.add(documentObject);
console.log(weakSet.has(documentObject));
Output:
true
For a different object, the result is false.
JavaScript
console.log(weakSet.has({}));
Output:
false
10.3 delete()
JavaScript
const weakSet = new WeakSet();
const item = {};
weakSet.add(item);
console.log(weakSet.has(item));
weakSet.delete(item);
console.log(weakSet.has(item));
Output:
true
false
11. WeakSet vs Set
|
Feature
|
Set
|
WeakSet
|
| --- | --- | --- |
|
Stores individual values
|
Yes
|
Yes
|
|
Stores objects
|
Yes
|
Yes
|
|
Stores primitive values
|
Yes
|
No
|
|
size property
|
Yes
|
No
|
|
add()
|
Yes
|
Yes
|
|
has()
|
Yes
|
Yes
|
|
delete()
|
Yes
|
Yes
|
|
Iteration
|
Yes
|
No
|
|
forEach()
|
Yes
|
No
|
|
Weak references
|
No
|
Yes
|
Set example
JavaScript
const set = new Set();
set.add("JavaScript");
set.add("Python");
console.log(set.size);
Output:
2
WeakSet example
JavaScript
const weakSet = new WeakSet();
const object1 = {};
const object2 = {};
weakSet.add(object1);
weakSet.add(object2);
console.log(weakSet.has(object1));
Output:
true
WeakSet is intended for tracking object identities rather than maintaining a collection that you can enumerate.
12. Practical Example: Tracking Processed Objects
One common use of WeakSet is to keep track of objects that have already been processed.
Consider a program that processes user objects.
JavaScript
const processedUsers = new WeakSet();
function processUser(user) {
if (processedUsers.has(user)) {
console.log("User already processed");
return;
}
processedUsers.add(user);
console.log("Processing user:", user.name);
}
const user1 = {
name: "Rahul"
};
processUser(user1);
processUser(user1);
Output:
Processing user: Rahul
User already processed
Explanation
During the first call:
-
The object is not in the WeakSet.
-
The object is added.
-
The processing operation takes place.
During the second call:
-
The object is already present.
-
The function detects that it has been processed.
-
The function avoids repeating the operation.
Why WeakSet is useful
If user1 becomes unreachable elsewhere, the WeakSet does not prevent it from becoming eligible for garbage collection.
This is useful for tracking objects without requiring a separate cleanup mechanism.
13. WeakMap and WeakSet Garbage Collection
Garbage collection is the process through which JavaScript engines reclaim memory occupied by objects that are no longer reachable.
Strong reference
A strong reference keeps an object reachable.
JavaScript
let user = {
name: "Rahul"
};
As long as user refers to the object, the object is reachable through that variable.
Weak reference
WeakMap and WeakSet do not keep their object keys or values alive solely through the collection.
JavaScript
let user = {
name: "Rahul"
};
const weakSet = new WeakSet();
weakSet.add(user);
user = null;
The object may become eligible for garbage collection.
Important clarification
Garbage collection is not immediate or predictable.
The following statements are not guaranteed:
-
The object is removed immediately after setting the variable to
null. -
The WeakMap entry disappears at a specific time.
-
The programmer can inspect the exact number of remaining WeakMap entries.
JavaScript intentionally hides this information to allow garbage collection to work without exposing object-lifetime details.
14. Why WeakMap and WeakSet Cannot Be Iterated
WeakMap and WeakSet do not support iteration methods.
For example:
JavaScript
const weakMap = new WeakMap();
const user = {};
weakMap.set(user, "User data");
console.log(weakMap.keys());
This throws a TypeError because WeakMap does not have a keys() method.
Similarly:
JavaScript
const weakSet = new WeakSet();
weakSet.add({});
console.log(weakSet.values());
This also throws a TypeError.
Why is iteration not supported?
Suppose a WeakMap allowed you to retrieve all keys.
If the garbage collector could remove unreachable objects at any time, the collection could change without any direct operation by the programmer.
This would make the result of iteration dependent on garbage collection timing.
To avoid exposing this unpredictable behavior, WeakMap and WeakSet do not provide collection-wide enumeration.
Practical consequence
You can check a specific object:
JavaScript
weakMap.has(user);
But you cannot ask:
JavaScript
// Not supported
weakMap.getAllKeys();
If you need to inspect all stored entries, use a normal Map or Set.
15. WeakMap and WeakSet with DOM Elements
WeakMap and WeakSet are useful when working with browser DOM elements.
For example, an application may need to associate information with HTML elements.
WeakMap example
JavaScript
const elementData = new WeakMap();
const button = document.createElement("button");
button.textContent = "Click Me";
elementData.set(button, {
type: "primary",
action: "submit"
});
console.log(elementData.get(button));
Output:
{ type: "primary", action: "submit" }
The WeakMap associates metadata with the button object.
WeakSet example
JavaScript
const initializedElements = new WeakSet();
const input = document.createElement("input");
function initializeElement(element) {
if (initializedElements.has(element)) {
return;
}
initializedElements.add(element);
console.log("Element initialized");
}
initializeElement(input);
initializeElement(input);
Output:
Element initialized
The second call does not initialize the element again.
Real-world applications
These techniques can be useful for:
-
Tracking initialized DOM elements.
-
Associating metadata with components.
-
Avoiding duplicate event setup.
-
Managing object-specific state.
-
Implementing libraries that work with DOM elements.
16. Important Differences Between WeakMap and WeakSet
|
Feature
|
WeakMap
|
WeakSet
|
| --- | --- | --- |
|
Collection type
|
Key-value collection
|
Object collection
|
|
Stores keys
|
Yes
|
No separate keys
|
|
Stores values
|
Yes
|
Stores objects/symbols as members
|
|
Access using get()
|
Yes
|
No
|
|
Check using has()
|
Yes
|
Yes
|
|
Add using set()
|
Yes
|
No
|
|
Add using add()
|
No
|
Yes
|
|
Remove using delete()
|
Yes
|
Yes
|
|
Object association
|
Metadata or cache
|
Membership tracking
|
|
Iteration
|
Not supported
|
Not supported
|
|
size
|
Not supported
|
Not supported
|
Simple way to remember
-
WeakMap: Object → Associated data.
-
WeakSet: Object → Is this object present?
17. When Should You Use WeakMap?
Use WeakMap when you want to associate additional