What is a WeakSet
In modern JavaScript (ES6 and beyond), a WeakSet is a collection of garbage-collectible values, including objects and non-registered symbols. Garbage-collectible values are values that can be deleted by the garbage collector when they are not needed anymore. The garbage collector is a program that automatically frees up memory by deleting objects that are no longer used. In JavaScript, most primitive data types like numbers or strings are NOT garbage-collectible since they can be arbitrarily created and don’t have a lifetime. Objects and non-registered symbols are garbage-collectible because they have a lifetime and can be referenced by other values.
The difference between a WeakSet and a regular Set is that a WeakSet can only contain objects and symbols, while a Set can contain any data types such as strings, numbers, objects, etc. Another difference is that a WeakSet is weak, meaning references to objects in a WeakSet are held weakly. If no other references to a value stored in the WeakSet exist, those values can be garbage collected1. This also means that a WeakSet does not have size
property, clear()
, keys()
, values()
, entries()
, forEach()
methods, and is NOT iterable.
Use cases of WeakSet
The main purpose of the existence of WeakSet is to save memory and avoid memory leaks. Some real-world use cases of WeakSet are:
- Use WeakSet to store DOM elements that are dynamically created and removed from the document. This way, you can avoid memory leaks and improve performance.
- Use WeakSet to store event listeners that are attached to DOM elements. This way, you can avoid memory leaks and improve performance.
- Use WeakSet to store objects that are used as keys in a Map or a Set. This way, you can avoid memory leaks and improve performance.
Creating a WeakSet
Creating an empty WeakSet
You can use the WeakSet()
constructor with no arguments to create an empty WeakSet. You can later add new objects to that WeakSet by calling the add()
method.
Example:
// create an empty WeakSet
const ws = new WeakSet();
// create some object
const foo = {};
const bar = {
a: 1,
b: 2,
c: 'Sling Academy',
};
// add the objects to the WeakSet
ws.add(foo);
ws.add(bar);
console.log(ws);
Output (Chrome console):
Creating a WeakSet with initial values
You can create a WeakSet with initial values by using the WeakSet()
constructor with an iterable object as an argument. This will create a WeakSet with the objects from the iterable object. The iterable object must only contain objects, otherwise, it will throw a TypeError.
Example:
// create an object
const foo = {};
// create another object
const bar = {name: "slingacademy.com"};
// create a WeakSet
const ws = new WeakSet([foo, bar]);
If you try to create a WeakSet with primitive values, you will end up with an error:
// Don't do this
let ws = WeakSet([1, 2, 3, 4, 5])
WeakSet methods & properties
WeakSet has three methods and two properties. The methods are:
add(value)
: Appends a new object with the given value to the WeakSet object.delete(value)
: Removes the element associated with the value.WeakSet.prototype.has(value)
will returnfalse
afterward.has(value)
: Returns a boolean asserting whether an element is present with the given value in the WeakSet object or not.
The properties are:
constructor
: Returns the function that created an instance’s prototype. This is the WeakSet function by default.[Symbol.toStringTag]
: The initial value of theSymbol.toStringTag
property is the string “WeakSet”. This property is used inObject.prototype.toString()
.
Real-world example
This article has a lot of words (with some basic examples). This may make you get bored. To consolidate your understanding of WeakSet, let’s build a tiny web project.
We will use a WeakSet to store DOM elements that are created dynamically. When an element is removed from the document, it is also removed from the WeakSet automatically by the garbage collector. This way, we can avoid memory leaks and improve performance.
Before seeing the code, let’s take a look at what we’re going to make:
Here is the complete code (with explanations):
<html>
<head>
<title>Sling Academy</title>
</head>
<body>
<p>
<button onclick="removeRandomElement()">
Remove Random Div Element
</button>
</p>
<script>
// Create a WeakSet to store DOM elements
const ws = new WeakSet();
// Create a function to create a new element with some text
const createNewElement = (text) => {
// Create a new div element
const div = document.createElement("div");
// Set the text content of the div
div.textContent = text;
// Add the div to the document body
document.body.appendChild(div);
// Add the div to the WeakSet
ws.add(div);
}
// Create some new elements with some text (when the page loads)
createNewElement("Welcome");
createNewElement("to");
createNewElement("Sling Academy");
// Create a function to remove a random element from the document
const removeRandomElement = () => {
// Get all the div elements in the document
// Get all the div elements in the document as an array
let divs = Array.from(document.querySelectorAll("div"));
// If there are any divs
if (divs.length > 0) {
// Pick a random index
const index = Math.floor(Math.random() * divs.length);
// Get the div at that index
let div = divs[index];
// Remove the div from the document body
document.body.removeChild(div);
// Clear the divs variable
divs.length = 0;
// Set the div variable to null
div = null;
// Check if the div is still in the WeakSet
console.log(ws.has(div));
}
}
</script>
</body>
</html>
That’s it. If you have any questions, please comment. Happy coding & have a nice day.