Back
Memory Management: Introduction to Weak References in JavaScript
The concept of weak references is relatively new in JavaScript. WeakSet and WeakMap are data structures introduced in JavaScript ES6; let's talk about them.
The management of the memory used during a program's execution determines the program's optimal performance. Therefore, this aspect of programming needs attention from software developers.
The garbage collector, a browser process that runs in the background in the JavaScript engine, helps to monitor the allocation of memory and determine when allocated memory is no longer needed, and then reclaims it. When declaring objects, references to these objects are strongly held. Therefore, these objects won’t be garbage-collected as long as their references still exist.
The concept of weak references is relatively new in JavaScript. WeakSet
and WeakMap
are data structures introduced in JavaScript ES6, and are the prospective approach to weakly reference an object in JavaScript. However, in a JavaScript program, using an object as a field/key to a WeakMap
or WeakSet
won't prevent it from being garbage-collected.
In this tutorial, we'll learn about weak references concerning WeakSet
and WeakMap
in JavaScript and how to utilize them for performance. First, let's quickly understand JavaScript garbage collection before later exploring WeakSet
and WeakMap
data structures.
A Quick Intro to Garbage Collection in JavaScript
Garbage collection refers to the cleaning of memory when objects or variables stored in that space are no longer in use. Memory management is important while writing JavaScript, as with every programming language. JavaScript, unlike C, is a high-level programming language designed to automatically clear memory when objects are no longer needed. While garbage collection is a complex issue, it is critical to grasp it when addressing references. Read more about memory management through garbage collection here.
The JavaScript engine controls the automated garage collecting procedure. When a value is accessible, it is guaranteed to be retained in memory and not garbage collected. A value can be reachable in two ways: First, a value is part of the base set of values that can be reached from the global variables. The function is being executed from its local variables. The alternative method is to access any value from the root via a reference or chain of references. Let’s assume we establish an item in a global variable; this object is reachable via the global space, and so it is deemed reachable.
Understanding Weak References in JavaScript
Let’s talk briefly about how weak references and strong references work so we can better understand how the WeakMap
and WeakSet
work. A weak reference is a reference to an object, the sole reference to the object in memory, and does not prohibit garbage collection.
Let’s apply this idea to the preceding example of a strong reference, and then apply it in setting a weak reference. We’ll ignore the usage of WeakMap
for the time being, as we’ll cover it in greater detail later. For now, consider the following examples of weak reference behavior:
In a strong reference, the reference to the original microsoft
object will remain, while the microsoft
object stays in the WeakMap
and may be accessed without difficulty.
However, when we rename the variable to null and replace the reference with the original microsoft
object, the original object in memory contains the weak reference back to the WeakMap
that we constructed.
This implies that the microsoft
object will be deleted from memory, and we’ll assign the WeakMap
to the next time the JavaScript engine performs a garbage collection procedure.
The main distinction between strong and weak references is that a strong reference prevents an item from being garbage collected, but a weak reference does not.
JavaScript employs strong references by default for all of its references, and the only method for using weak references is with a WeakMap
or a WeakSet
. While a strong reference would prohibit the garbage collection of an item even if it were the sole object accessing it, a weak reference would not. Let’s see this in the example below:
We can insert the object into an array and delete the reference to the original object by changing its value to null through generating it as an object.
Although we can no longer access the object via the microsoft
variable due to a strong reference between the company
array and the object, the object is still preserved in memory. It can be accessed via company[0]
.
In other words, the strong reference prevents the item from being removed from memory via garbage collection.
The Difference Between Map and WeakMap
As we learned about garbage collection, the JavaScript engine stores a value in memory for as long as it is accessible. Let's look at some examples:
While a data structure is in memory, its properties are considered accessible, so they’re typically preserved. If we store an item in an array, the object may still be retrieved even if it has no other references, as long as the array is in memory.
The Map
object keeps track of key-value pairs and remembers the order in which they were added. Any value (objects and primitive values alike) can be used as a key or a value.
This means the object is similar to an object in that we can store key-value pairs and retrieve the values within the Map
using the key. However, unlike a typical JavaScript object, we must use the .get()
function to get the values.
A WeakMap
is quite similar to a Map
, except the references it stores are weak references, which means it will not prevent garbage collection from deleting items it refers to if they are not firmly linked elsewhere.
WeakMap
also has the disadvantage of not being enumerable, due to the weak references.
Finally, we must use objects as keys, but the values can be anything, such as text or an integer. Here is an example of a WeakMap
and the techniques that can be applied to it:
WeakMap()
can also be used to store additional data. Let’s assume we're developing a food delivery app platform with software that counts the number of people who use the application. In this scenario, we'd like to reduce the count when customers leave. This task would be difficult to accomplish with Map
, but it’s relatively simple with WeakMap()
:
When using Map()
, we must clean countPerson
every time a client leaves; otherwise, it would take up space by continually increasing memory. However, by using WeakMap()
, we do not need to do this cleaning step; it is automatically garbage-collected.
The Difference Between Set and WeakSet
The Set
object allows us to store unique values of any type, whether they’re raw values or object references. A set, like an array, lacks a key-value pair. Using array methods for...of
and .forEach()
, we can iterate through a set of arrays:
WeakSet
objects are object collections. Like Sets
, each object in a WeakSet
can only appear once; all objects in a WeakSet
's collection are unique.
The following are the primary distinctions between the Set
object and the WeakSet
object: WeakSets
are merely collections of items. They, unlike Sets
, cannot hold arbitrary values of any type. The WeakSet
is weak, which means that references to items in it are kept weak. If there are no additional references to an item in the WeakSet
, those objects can be garbage collected.
Simply put, a Set
is similar to an array in that it can only contain unique values, but it can still be iterated using techniques like for
loops and .forEach
.
WeakSet
, like a Set
, is a collection of items distinct from one another. Still, it varies because WeakSet
may only hold objects and cannot have arbitrary values like texts or integers.
Finally, as the name implies, WeakSets
are weak, as they employ weak references.
Using weak references has the interesting side effect of rendering WeakSet
uncountable. There is no means to iterate through the items included within the collection since there is no list of current objects stored in it; they are weakly referenced and may be destroyed at any moment.
A WeakSet
is a collection of one-of-a-kind items. WeakSets
, as the name implies, make use of weak references. WeakSet()
has the following properties:
It can only hold items
Objects in the set may be accessible from other locations
It is not possible to loop through it
WeakSet()
, like Set()
, has access to similar .add()
, .has()
, and .delete()
methods.
Here's an example of WeakSet
in action, along with the methods we can call on it:
Conclusion
Although WeakMaps
and WeakSets
are rarely used in JavaScript, they are useful for rare scenarios and building a good foundation. Strong references are used in most cases. WeakMaps
and WeakSets
temporarily store data as they save us the headache of clearing or cleaning up the memory.