With ES6, a new data structure called WeakMaps is introduced. It’s introduced along regular Maps.
Like Maps, WeakMaps stores data as key-value pairs.
The difference is that WeakMaps don’t interfere with garbage collection since once the reference to the objects is destroyed, the entry with the destroyed object as the key can’t be accessed and it’s garbage collected.
Use Cases for WeakMaps
Since the entry is destroyed as soon as the object which is the key for the WeakMap is destroyed, it’s more efficient than Maps and also more private since only the code with the object reference can access the entry stored in the WeakMap.
This means that there’re a few uses cases for WeakMaps:
- We can use it to keep private data about a specific object and only allow people with the object to access a value
- Keeping data without using extra resources
- Keep temporary data
- Storing key-value pairs that can be destroyed on the fly without explicitly doing so.
Defining WeakMaps
We can define WeakMaps as follows:
let jane= {
name: "John"
};
let weakMap = new WeakMap([
[jane, 1]
]);
Then we can access the entry with the object reference with the get
method:
console.log(weakMap.get(jane));
Keys in a WeakMap can only be objects. If we try to create an entry with a primitive value, we’ll get an error.
For example, if we try to run:
let weakMap = new WeakMap([
[1, 1]
]);
We’ll get the error ‘Uncaught TypeError: Invalid value used as weak map key.’
Once the object reference is destroyed, then we can no longer access the key-value pair that had the destroyed object as the key.
For example, if we write:
let jane = {
name: "Jane"
};
let weakMap = new WeakMap([
[jane, 1]
]);
jane = null;
console.log(weakMap.get(jane));
Then we get undefined
from the console.log
since jane
is set to null
, so the reference of the original object was removed from memory.
Manipulating WeakMaps
Unlike Maps, WeakMaps has fewer methods for manipulating the entries. WeakMap instances only have the get
, set
, delete
, and has
methods.
get
The get
method is used for looking up a value with the given key. It takes one argument, which is the key that we used to look up the value with. We can use it as follows:
let jane = {
name: "Jane"
};
let weakMap = new WeakMap([
[jane, 1]
]);
console.log(weakMap.get(jane));
Then we get 1 as the value.
Note that we have to use the exact object reference to get the value from a WeakMap. A new object that looks like the original reference won’t work. For example, if we write:
let jane = {
name: "Jane"
};
let weakMap = new WeakMap([
[jane, 1]
]);
console.log(weakMap.get({
name: "Jane"
}));
We will getundefined
because we need to pass in jane
to get 1. Any other object that has the same content doesn’t have the same reference in memory. This is why we can’t get the value with anything else other than the original key.
set
The set
method is used to add a new key-value pair to the WeakMap. It takes an object as the first argument for the key, and any value for the second argument for the value of the corresponding key.
For instance, we can use the set
method as follows:
let jane = {
name: "Jane"
};
let john = {
name: "john"
};
let weakMap = new WeakMap([
[jane, 1]
]);
weakMap.set(john, 2);
console.log(weakMap.get(john));
delete
The delete
method takes one argument, which is an object for the key
. We can remove it with the object reference as follows:
let jane = {
name: "Jane"
};
let john = {
name: "john"
};
let weakMap = new WeakMap([
[jane, 1]
]);
weakMap.set(john, 2);
weakMap.delete(john)
console.log(weakMap.get(john));
We would get undefined
from the last line after we called delete
with john
passed in since we removed the key-value pair from the WeakMap.
has
The has
method lets us check if a value exists for a given key. It takes one argument, which is the key that we want to look up the value with.
For example, we can use it as follows:
let jane = {
name: "Jane"
};
let weakMap = new WeakMap([
[jane, 1]
]);
console.log(weakMap.has(jane));
We will get true
from the console.log
output since we have an entry with jane
as the key.
Once again, like the get
method, we have to use the exact object reference as the key to get true
from the has
method.
Therefore, the following will log false
:
let jane = {
name: "Jane"
};
let weakMap = new WeakMap([
[jane, 1]
]);
console.log(weakMap.has({
name: "Jane"
}));
We will get false
because what we pass in isn’t the exact object reference for the [jane, 1]
. The key is jane
, not another object that looks like jane
since the reference in memory would be different.
WeakMaps are handy for storing data that can be destroyed easily since the keys are exact object references. It’s also handy for storing data that can be garbage collected once references to it destroyed. The ease of garbage collection makes freeing up resources an easy process.
Also, it’s great for private data since the keys can be destroyed easily. Once the key object is no longer in memory, then the entry with the given key is gone forever.