Categories
JavaScript

Storing Data Efficiently or Privately with JavaScript WeakMaps

Spread the love

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.

Leave a Reply

Your email address will not be published.

If you like the content of this blog, subscribe to my email list to get exclusive articles not available to anyone else.