ECMAScript 6 collections, Part 3: WeakMaps
Weakmaps are similar to regular maps in that they map a value to a unique key. That key can later be used to retrieve the value it identifies. Weakmaps are different because the key must be an object and cannot be a primitive value. This may seem like a strange constraint but it’s actually the core of what makes weakmaps different and useful.
A weakmap holds only a weak reference to a key, which means the reference inside of the weakmap doesn’t prevent garbage collection of that object. When the object is destroyed by the garbage collector, the weakmap automatically removes the key-value pair identified by that object. The canonical example for using weakmaps is to create an object related to a particular DOM element. For example, jQuery maintains a cache of objects internally, one for each DOM element that has been referenced. Using a weakmap would allow jQuery to automatically free up memory associated with a DOM element when it is removed from the document.
The ECMAScript 6
WeakMap type is an unordered list of key-value pairs where the key must be a non-null object and the value can be of any type. The interface for
WeakMap is very similar to that of
Map in that
get() are used to add data and retrieve data, respectively:
var map = new WeakMap(), element = document.querySelector(".element"); map.set(element, "Original"); // later var value = map.get(element); console.log(value); // "Original" // later still - remove reference element.parentNode.removeChild(element); element = null; value = map.get(element); console.log(value); // undefined
In this example, one key-value pair is stored. The key is a DOM element used to store a corresponding string value. That value was later retrieved by passing in the DOM element to
get(). If the DOM element is then removed from the document and the variable referencing it is set to
null, then the data is also removed from the weakmap and the next attempt to retrieve data associated with the DOM element fails.
This example is a little bit misleading because the second call to
map.get(element) is using the value of
element was set to) rather than a reference to the DOM element. You can’t use
null as a key in weakmaps, so this code isn’t really doing a valid lookup. Unfortunately, there is no part of the interface that allows you to query whether or not a reference has been cleared (because the reference no longer exists).
Note: The weakmap
set() method will throw an error if you try to use a primitive value as a key. If you want to use a primitive value as a key, then it’s best to use
Weakmaps also have
has() for determining if a key exists in the map and
delete() for removing a key-value pair.
var map = new WeakMap(), element = document.querySelector(".element"); map.set(element, "Original"); console.log(map.has(element)); // true console.log(map.get(element)); // "Original" map.delete(element); console.log(map.has(element)); // false console.log(map.get(element)); // undefined
Here, a DOM element is once again used as the key in a weakmap. The
has() method is useful for checking to see if a reference is currently being used as a key in the weakmap. Keep in mind that this only works when you have a non-null reference to a key. The key is forcibly removed from the weakmap by using
delete(), at which point
Both Firefox and Chrome have implemented
WeakMap, however, in Chrome you need to manually enable ECMAScript 6 features: go to
Uses and Limitations
In many cases, a regular map is probably what you want to use. Weakmaps are limited in that they aren’t enumerable and you can’t keep track of how many items are contained within. There also isn’t a way to retrieve a list of all keys. If you need this type of functionality, then you’ll need to use a regular map. If you don’t, and you only intend to use objects as keys, then a weakmap may be the right choice.
- WeakMaps Strawman (ECMA)
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.