JavaScript WeakMap Data Structure

JavaScript WeakMap Data Structure with Examples

In this article, I am going to discuss JavaScript WeakMap Data Structure in detail with Examples. JavaScript ECMAScript6 (ES6) introduces four new data structures: Set, WeakSet, Map, and WeakMap. We already learned Set, WeakSet, and Map. Let’s start exploring and understanding the following pointers in detail about WeakMap in JavaScript.

  1. What is WeakMap in JavaScript?
  2. Where to use WeakMap in JavaScript?
  3. Features of JavaScript WeakMap DataStructure
  4. JavaScript WeakMap Methods
  5. How to Create a WeakMap Object in JavaScript?
  6. WeakMap Garbage Collection in JavaScript
  7. How to Add a Value to a WeakMap object in JavaScript?
  8. How to Get a Value associated with the key in WeakMap?
  9. How to Check if an element with the key exists in a WeakMap Object in JavaScript?
  10. How to Remove an element with the key from WeakMap?
  11. Map Vs WeakMap in JavaScript
What is WeakMap in JavaScript?

A WeakMap is the same as a Map except that key in WeakMap must be an object (not null). (objects are nothing but a data structure that allows us to store any kind of value. We will learn more about this in the object chapter.)

The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced. The WeakMap is different from Map as they can only contain keys which are objects.

Keys of WeakMap are of the type of object only. Primitive data types as keys are not allowed (e.g. a Symbol can’t be a WeakMap key). The reason why only objects are allowed as keys is that because primitive values are never garbage-collected. Hence if we try to use a primitive value, it will throw an error Type Error: Invalid value used in weak map.

The WeakMap object is used for storing key-value pairs. The WeakMap is different from Map is that keys must be an object, not a primitive value, and are weakly referenced. It holds the reference to the key objects weakly. This means that if there are not any other references to that key or if that object is deleted somewhere in the program, then the element in the WeakMap can be removed by the garbage collector by realizing the value mapped to that object.

As the name implies the WeakMap is they are weak, meaning references to the keys in the WeakMap are held weakly, which means that if there is no other reference to a keys objects stored in a WeakMap, It can garbage collected means the garbage collector will collect and free the memory of those object which has occupied the memory and not currently in use in any of our program or code. Garbage collection in JavaScript is performed automatically by JS Engine so the developer does not need to worry about it.

Since the object in WeakMap is automatically garbage-collected due to having a weak reference. Because of references being weak, WeakMap keys are not enumerable (i.e.: there is no method giving us a list of the keys).

WeakMap collection doesn’t contain iterable or the method that can return the list of keys. Hence WeakMap does not have a size property and we cannot determine its size.

Where to use WeakMap in JavaScript?

We can only use a WeakMap to check if a specified value is there or not.

  1. It can be used to store metadata about the DOM element in the browser.
  2. Another area where it can be used is Caching. When a function output should be captured or remembered (“cached”) so that the future calls on the same object reuse it, and we don’t have to compute it again.
Features of JavaScript WeakMap DataStructure
  1. WeakMap keys are objects (values can be arbitrary values)
  2. WeakMap keys are weakly held.
  3. We can’t clear a WeakMap
  4. In WeakMap, if there is no reference to a stored key object, they are automatically clean up by a garbage collector.
  5. In WeakMap, the objects are not iterable or enumerable. WeakMap can’t be iterated.
  6. As the WeakMap key object cannot be iterable hence we can’t access the size of WeakMap.
Syntax to use WeakMap in JavaScript

The below syntax created a new WeakMap
new WeakMap([iterable]);
The WeakMap constructor also accepts an optional iterable object whose elements are key-value pairs.
Iterable: If we provide an iterable object (usually an array) to the WeakMap constructor, all the elements of the iterable object will be added to the new WeakMap. null is treated as undefined.

JavaScript WeakMap Methods

The WeakMap object in JavaScript has three methods, all of them work the same as the Map methods:

JavaScript WeakMap Data Structure with Examples

How to Create a WeakMap Object in JavaScript?

The WeakMap constructor has an optional parameter/argument, which can be any type of iterable object (for example an array) containing two-element arrays of key/value pairs. All the elements of the iterable object will be added to the newly created WeakMap.

const object1 = {},
           object2 = function () { };
const weakmap = new WeakMap([[object1, 40], [object2, object1]]);

Example: JavaScript WeakMap example
<html>
<head>
    <title>JavaScript WeakMap example</title>
</head>
<body>
    <script>
        const object1 = {},
              object2 = { x: 10, y: 20 };
        let myWeakMap = new WeakMap([[object1, 40], [object2, object1]]);

        console.log("WeakMap example:", myWeakMap);
        console.log("type of myWeakMap:", typeof (myWeakMap));
        let result = myWeakMap instanceof WeakMap;
        console.log("check if myWeakMap instance of WeakMap:", result);
    </script>
</body>
</html>

Output:

Where to use WeakMap in JavaScript?

WeakMap Garbage Collection in JavaScript

As we know that A WeakMap doesn’t have a size, and we can never tell/identify how many elements are in it. A WeakMap is not enumerable, which means we cannot loop over it. The items inside of a WeakMap, if they no longer exist anywhere else in our application, they will get garbage collected and they’ll be removed from our WeakMap.

Let’s quickly go through an example of where we have a regular map and a regular WeakMap, and we’ll show exactly the difference here. We’ll create two objects here, then we’ll create two maps.

Example: WeakMap garbage collector example
<html>
<head>
    <title>JavaScript WeakMap garbage collector example</title>
</head>
<body>
    <script type="text/javascript">
        let student1 = { name: 'Shagufta' };
        let student2 = { name: 'JohnDoe' };

        var myStrongMap = new Map();
        var myWeakMap = new WeakMap();

        myStrongMap.set(student2, 'JohnDoe is the 2nd best Student!');
        myWeakMap.set(student1, 'Shagufta is the best Student!');

        student1 = null;
        student2 = null;

        console.log(myStrongMap);
        console.log(myWeakMap);

        /*
        Output
        Map {{name: "JohnDoe"} => "JohnDoe is the 2nd best Student!"} (1)
        myWeakMapMap {{name: "Shagufta"} => "Shagufta is the best Student!"} (1)
        */

        setTimeout(function () {
            console.log("1200ms later... waiting for garbage collection");
            console.log(myStrongMap);
            console.log(myWeakMap);
        }, 1200);

        setTimeout(function () {
            console.log("3200ms later... waiting for garbage collection");
            console.log(myStrongMap);
            console.log(myWeakMap);
        }, 3200);

        setTimeout(function () {
            console.log("6200ms later... waiting for garbage collection");
            console.log(myStrongMap);
            console.log(myWeakMap);
        }, 6200);

        /*
        Output (eventually)
        Map {{name: "JohnDoe"} => "JohnDoe is the 2nd best Student!"} (1)
        myWeakMapMap {} (0)
        */
    </script>
</body>
</html>

Output:

WeakMap Garbage Collection in JavaScript

In the above example, we have created these two objects and we are using them as keys in map and weakmap by adding them into it, and then we have deleted them. If we noticed, we have our myStrongMap, which still has an item in it. Whereas myWeakMap has nothing inside it because it’s been garbage collected. Note that it can take a couple of seconds.

We no longer have a student1 and student2 but myStrongMap is still containing this object that no longer exists. That is a memory leak called because there is no way for us to reference it whereas the WeakMap has totally got cleaned up by Garbage collection that has been performed and no longer reference is there.

If there is a situation where we need something like this, where it gets garbage collected and where we don’t have to do manually what is and what is not inside the map then that’s the case where we can refer WeakMap over Map.

Since garbage collection is not guaranteed to run, but GC may actually run after the first timeout. Hence, References to objects in the collection are held weakly. If there is no other reference to an object that existed in the WeakMap, they can be garbage collected.

How to Add a Value to a WeakMap Object in JavaScript?

To add a value to the key in a WeakMap, use the set() method. It Stored the value for the key, returns the WeakMap object itself. So we can chain set() method calls hence set() method is chainable.

myWeakMap.set(key, value)
chainable .set() method
myWeakMap.set(obj, 100).set(obj2, obj1);

Example: JavaScript WeakMap set() method example
<html>
<head>
    <title>JavaScript WeakMap set() method example</title>
</head>
<body>
    <script>
        const obj1 = {},//empty object
            obj2 = function () { },
            obj3 = window,
            obj4 = { a: 20, b: 40 },
            obj5 = new Date();

        let myWeakMap = new WeakMap();
        myWeakMap.set(obj1, 40);
        myWeakMap.set(obj2, 'function')
            .set(obj3, new Date())
            .set(obj4)
            .set(obj5)
            .set(obj4, 'hello')
            .set(obj5, 100);

        console.log("WeakMap after adding a value:", myWeakMap);//add unique object no duplicates

        try {
            myWeakMap.set(10, 20);//primitive value/value types(int, string and boolean)are not allowed as keys
        } catch (error) {
            console.log('Value types', error);
        }

        try {
            myWeakMap.set(Symbol(), 20);//Symbol is a value type as well, and they’re not allowed either.
        } catch (error) {
            console.log('Symbol', error);
        }
    </script>
</body>
</html>

Output:

Adding a Value to a WeakMap Object in JavaScript

As we can see from the above example, though we have added 7 elements in the WeakMap, it showing 5 elements in the output as it has removed the duplicate objects because of having a feature of storing unique objects also it shows that WeakMap doesn’t allow primitive value to be stored. We found that WeakMap has a limitation as compared to Map that every key must be an object not null and primitive types are not allowed as keys. Also, note that Symbol is value type as well but then they are not allowed as key. If we try to add Symbol in WeakMap then it will throw an error same can be seen in the above example.

How to Get a Value associated with the key in WeakMap?

To get a value associated with the key in a WeakMap, use the get() method. It returns the value associated with the key; else it returns undefined if the key doesn’t have any value associated with it in the WeakMap.

myWeakMap.get(key)

Example: JavaScript WeakMap get() method example
<html>
<head>
    <title>JavaScript WeakMap get() method example</title>
</head>
<body>
    <script>
        const obj1 = {},//empty object
            obj2 = function () { },
            obj3 = window,
            obj4 = { a: 20, b: 40 },
            obj5 = new Date();

        let myWeakMap = new WeakMap();
        myWeakMap.set(obj1, 40);
        myWeakMap.set(obj2, 'function')
            .set(obj3, new Date())
            .set(obj4); 

        console.log("WeakMap after adding a value:", myWeakMap);//add unique object no duplicates

        console.log("WeakMap get value associated to object obj2: ", myWeakMap.get(obj2));
        console.log("WeakMap get value associated to object obj4: ", myWeakMap.get(obj4));
    </script>
</body>
</html>

Output:

Getting a Value associated with the key in WeakMap

How to Check if an element with the key exists in a WeakMap Object in JavaScript?

To check if a WeakMap contains an element with a specified key, call the has() method on it. It returns true if an element with a specified key exists in the WeakMap, otherwise false.

myWeakMap.has(key)

Example: JavaScript WeakMap has() method example
<html>
<head>
    <title>JavaScript WeakMap has() method example</title>
</head>
<body>
    <script>
        const obj1 = {},//empty object
            obj2 = function () { },
            obj3 = window,
            obj4 = { a: 20, b: 40 },
            obj5 = new Date();

        let myWeakMap = new WeakMap();
        myWeakMap.set(obj1, 40);
        myWeakMap.set(obj2, 'function')
            .set(obj3, new Date())
            .set(obj4);

        console.log("WeakMap after adding a value:", myWeakMap);//add unique object no duplicates

        console.log("Check if myWeakMap contains obj1: ", myWeakMap.has(obj1));
        console.log("Check if myWeakMap contains obj5: ", myWeakMap.has(obj5));
    </script>
</body>
</html>

Output:

Checking if an element with the key exists in a WeakMap

How to Remove an element with the key from WeakMap?

Deleting an element from a WeakMap is as simple as calling the delete() method, and passing in the element we want to remove. To remove an element/value with a specified key from a WeakMap, use the delete() method.

myWeakMap.delete(key)

This method will return true if the value/element existed in the WeakMap and has been removed, otherwise false.

Example: JavaScript WeakMap delete() method example
<html>
<head>
    <title>JavaScript WeakMap delete() method example</title>
</head>
<body>
    <script>
        const obj1 = {},//empty object
            obj2 = function () { },
            obj3 = window,
            obj4 = { a: 20, b: 40 },
            obj5 = new Date();

        let myWeakMap = new WeakMap();
        myWeakMap.set(obj1, 40);
        myWeakMap.set(obj2, 'function')
            .set(obj3, new Date())
            .set(obj4);

        console.log("WeakMap after adding a value:", myWeakMap);//count:4
        console.log("Does WeakMap has obj1 element?", myWeakMap.has(obj1));
        console.log("WeakMap deleting an existing value(obj1):", myWeakMap.delete(obj1));

        console.log("Does WeakMap has obj5 element?", myWeakMap.has(obj5));
        console.log("WeakMap deleting an non-existing value(obj5):", myWeakMap.delete(obj5));//obj5 is not added into myWeakMap hence returning false
        console.log("WeakMap after deleting a value:", myWeakMap);//count:3
    </script>
</body>
</html>

Output:

Removing an element with the key from WeakMap

Map Vs WeakMap in JavaScript

Map

WeakMap

The map doesn’t have garbage collection features.WeakMap allows garbage collection of objects. This prevents memory leaks.
Map has a size property.WeakMap doesn’t have a size property.
Map is iterable.WeakMap is not iterable.
Map have clear(), keys(), values, entries() and forEach() methodsWeakMap doesn’t have these methods.
Key in Map can be anything (Object, Primitive data types such as string, number, etc).Key in WeakMap must be of type Object (not null). Primitive data types (string, number, or Boolean) as keys are not allowed (e.g. a Symbol can’t be a WeakMap key).
In Map, if an object as the key is used, then while the Map exists, that object exists as well. It occupies memory and may not be garbage collected.In WeakMap, if an object as the key is used, and there are no other references to that object – it will be removed from memory (and from the map) automatically.

Here, in this article, I try to explain the JavaScript WeakMap Data Structure with examples. I hope this JavaScript WeakMap Data Structure article will help you with your need. I would like to have your feedback. Please post your feedback, question, or comments about this JavaScript WeakMap Data Structure with Examples article.

Leave a Reply

Your email address will not be published. Required fields are marked *