DEV Community

Sal Rahman
Sal Rahman

Posted on • Updated on

How to use WeakMap in JavaScript

You've seen Map.

Then there's WeakMap.

WeakMap doesn't allow you to iterate over the key-value pairs that you add to it.

const map = new WeakMap([[{}, {}], [{}, {}]]);

for (const el of map) { // TypeError: map is not iterable
  console.log(el);
}
Enter fullscreen mode Exit fullscreen mode

Effectively, whatever that you store in WeakMap, you can't know what's in it.

But it does have a benefit: a WeakMap deletes key-value pairs, when the original key is garbage-collected.

Garbage Collection

Whenever you create an object, it gets added to memory. There is absolutely no way to explicitly delete it from memory.

This is where garbage-collection comes in. If you lose reference to the object, the garbage collector assumes that the object is no longer needed, freeing up memory on the user's machine.

Memory Leaks

Although JavaScript is a garbage-collected language, there are ways to cause a memory leak; that is, adding data to memory that don't end up getting freed, eating up available memory on the user's machine.

Here are three steps to cause memory leaks in JavaScript:

  1. add data to either an array, Set, object, or Map, and then
  2. never losing reference to any of them
  3. never writing any logic that revisits them to delete any unneeded data

Object Purity

Before I demonstrate how to use WeakMaps, I will first highlight the importance of object purity.

Some problems require us to maintain information about an object that we have no control over. Usually, these objects come from other libraries that we did not write.

There are two approaches to maintaining information about an object (that I can think of).

The first being that we can modify the object directly. In the interest of defensive programming, modifying objects directly could introduce bugs that would be hard to debug. And if we do discover the cause of the problem, we may eventually conclude: object purity is important.

This brings us to our second approach. Instead of modifying the object directly, we can instead map the original object to some other data. There are three JavaScript primitives that we can use for this: object, Map, and WeakMap.

Object and Map requires us to write logic that revisits them to clean them up, in order to avoid memory leaks. WeakMaps, on the other hand, does not require us to revisit it to delete unneeded key-value pairs.

Using WeakMap

So with memory leaks in mind, and with our intention to maintain object purity, a WeakMap will allow us to maintain metadata, and let garbage collection take over for data we no longer care about.

Let's assume one of our problems involves maintaining a counter for the number of times an object was accessed.

const map = new WeakMap();

function dataMeta(obj) {
  let data = map.get(obj);

  if (!data) {

    // Replace this code with whatever data that you want to
    // maintain.
    data = { count: 0 };

    map.set(obj, data);
  }

  // Replace this code with whatever mutations that you want
  // to introduce.
  data.count++;

  return data;
}
Enter fullscreen mode Exit fullscreen mode

And below is the above function in action.

console.log(dataMeta({})); // { count: 1 }

console.log(dataMeta({})); // { count: 1 }

const someData = {};

console.log(dataMeta(someData)); // { count : 1 }

console.log(dataMeta(someData)); // { count : 2 }
Enter fullscreen mode Exit fullscreen mode

And, if we are to lose reference to someData (perhaps we've left a function's scope that held that variable), then there will be no way to retrieve that object.

So what happens? Garbage collection. The WeakMap associated with map will no longer hold the data associated with the someData.

Conclusion

JavaScript cleans up memory that is no longer in use.

However, it is still possible to introduce memory leaks in JavaScript, by adding values to unbounded collection types, more specifically, array, object, Map, and Set.

Therefore, the aforementioned primitives are not good for holding meta information about an object.

This is where WeakMap will be useful.

Top comments (0)