In JavaScript, objects and arrays are often used to store and manage data.
But JavaScript also provides four powerful built-in data structures that are often more useful and efficient than plain objects or arrays when you need uniqueness or flexible key types.
- WeakSet
- WeakMap
- Set
- Map
Let’s learn about each one in detail.
WeakSet in JavaScript
A WeakSet is similar to a Set, but it only stores objects and is not iterable.
If you store an object inside a regular structure like an array, Set, or Map, that object is strongly referenced. This means as long as it's stored there, JavaScript won’t remove it from memory, even if your code no longer uses it.
But items in WeakSet hold weak references. This means they don’t prevent garbage collection. If there are no other references to an object (other than being in a WeakSet), the JavaScript engine is free to automatically delete it from memory.
Creating a WeakSet
You can create a WeakSet by using new WeakSet() syntax.
const ws = new WeakSet();
console.log(ws); // Output: WeakSet []WeakSet Methods
JavaScript provides the following methods to work with WeakSet.
add(object):
The add(object) method adds an object to the WeakSet.
const ws = new WeakSet();
const user = { id: 1 };
ws.add(user);If you later remove all other references to user, it can be automatically removed from memory.
has(object):
The has(object) method returns true if an object exists in the WeakSet.
ws.has(user); // Output: truedelete(object):
The delete(object) method removes the object from the WeakSet.
ws.delete(user); // Output: trueLimitations of WeakSet
- Only works with objects (not primitives).
- You can’t loop over a WeakSet.
- No
.size,.clear(), or.forEach().
Use Case of WeakSet
WeakSet is useful for tracking objects privately.
const visitedNodes = new WeakSet();
function markVisited(node) {
if (!visitedNodes.has(node)) {
visitedNodes.add(node);
console.log("Processing:", node.name);
}
}
const nodeA = { name: "Node A" };
const nodeB = { name: "Node B" };
markVisited(nodeA); // Output: Processing: Node A
markVisited(nodeB); // Output: Processing: Node B
markVisited(nodeA); // No outputHere,
- You create a WeakSet to track objects (in this case, nodeA and nodeB).
- A WeakSet only allows objects (not primitives) and holds weak references, meaning it won’t prevent garbage collection.
-
function markVisited(node) {...}checks whether the node has already been processed (i.e., is in visitedNodes). If not, it:- Adds it to the WeakSet (so next time it won't be processed again)
- Logs the message
nodeAandnodeBare just plain objects.markVisited(nodeA); // Output: Processing: Node A: nodeA is not in visitedNodes, so it's processed and added.markVisited(nodeB); // Output: Processing: Node B: nodeB also gets added and processed.markVisited(nodeA); // No output: nodeA is already in the WeakSet, so nothing happens, it skips processing.
WeakMap in JavaScript
A WeakMap is similar to a Map, but the keys of a WeakMap must be objects and the values can be anything.
The keys are weakly referenced, that means if the object is no longer used anywhere else, it can be garbage-collected.
WeakMap is not iterable and useful for storing private data tied to objects.
Creating a WeakMap
You can create a WeakMap by using new WeakMap() syntax.
const wm = new WeakMap();
console.log(wm); // Output: WeakMap(0)WeakMap Methods
JavaScript provides the following methods to work with WeakMap.
set(object, value):
The set(object, value) method adds a key-value pair to the WeakMap where key is object.
const wm = new WeakMap();
const user = {};
wm.set(user, { role: "admin" });get(object):
The get(object) method is used to retrieve the value of a key.
wm.get(user); // Output: Object { role: "admin" }has(object):
The has(object) method is used to check if a key exists in a WeakMap.
wm.has(user); // Output: truedelete(object):
The delete(object) method is used to remove the key-value pair.
wm.delete(user); // trueLimitations of WeakMap
- Keys must be objects.
- You can’t loop over a WeakMap.
- No
.forEach(),.keys(),.size, orfor...of.
Use Case of WeakMap
WeakMap is useful for storing private data per object.
const privateData = new WeakMap();
function createUser(name) {
const user = {};
privateData.set(user, { name });
return {
sayHi() {
console.log(`Hi, I'm ${privateData.get(user).name}`);
},
};
}
const u1 = createUser("Shefali");
u1.sayHi(); // Output: Hi, I'm ShefaliHere,
- You create a WeakMap to hold private data for objects.
- In the function
createUser,const user = {};: a new empty object user is created.- You store its
nameinside theprivateDataWeakMap usinguseras the key. privateDatanow looks like:{ user → { name: "Shefali" } }.return {...},- The returned object has a
sayHi()method that can access the user's name usingprivateData.get(user). - But the
userobject itself is not exposed, it’s trapped in the closure.
- The returned object has a
const u1 = createUser("Shefali");create a user named "Shefali" and call thesayHi()method.u1.sayHi();printsHi, I'm Shefalito the console.privateDataisn't accessible outside the closure and won't prevent garbage collection ifu1is discarded.
Tips
- Use
WeakSetandWeakMaponly when working with objects. - They’re ideal for cases where you don’t want to manually manage memory.
- They help implement encapsulation, especially in libraries and frameworks.
👉 Next tutorial: JavaScript ES6 Modules: import / export