Javascript tips — Map and WeakMap

Leonardo Bruno Lima
3 min readApr 9, 2018

--

Photo by Luca Bravo on Unsplash

Hi, let’s talk about these four data structures that were introduced in ECMAScript 2015 and why use each one.

Map

“ The Map object holds key-value pairs. Any value (both objects and primitive values) may be used as either a key or a value.” MDN

The Map data structure in ECMAScript 2015 (or ES6 or ES2015) lets you use arbitrary values as keys. Before talk about Map, let’s see what we can do without it (before ES6):

We can create Object literals as Maps like this:

let old_map = {
"key1":"value1",
"key2":"value2",
"key3":"value3",
}
console.log(old_map.key1); // output value1
console.log(old_map.toString()) // output [object Object]

But we can have some problems, for example:

...old_map.toString = "new value" // this is an acceptable instruction
old_map.toString(); // Uncaught TypeError: map.toString is not a function

Another problem of using object literals as “map”: All keys can only be strings! The problem is when attempting to use a primitive value as a string, javascript will convert it to a string behind the scenes and without notification, which can cause unexpected results.

Now let’s see Map in action:

let map = new Map();map.set('key1', 123);
console.log(map.get('key1')); // output 123
console.log(map.has('key1')) // output true
console.log(map.delete('key1')); // output true (removed)
console.log(map.has('key1')); // output false

Very straightforward, right? there are many properties and methods, you can find out more in MDN.

You can initialize a map passing some params, like this:

let map = new Map([[ 1, 'one' ],[ 2, 'two' ],[ 3, 'three' ]]);console.log(map.size); // output 3
map.clear();
console.log(map.size); // output 0

Or chaining set methods:

let map = new Map()
.set(1, 'one')
.set(2, 'two')
.set(3, 'three');
console.log(map.size); // output 3
map.clear();
console.log(map.size); // output 0

Let’s talk about the keys. In Map object any value can be set as key, even an object:

let map = new Map();const key1 = {};
map.set(key1, 'I love');
console.log(map.get(key1)); // output I love
const key2 = {};
map.set(key2, 'Javascript');
console.log(map.get(key2)); // output Javascript

Let’s see how iterate over it:

let map = new Map([[ 1, 'one' ],[ 2, 'two' ],[ 3, 'three' ]]);for (let key of map.keys()) {
console.log(key);
}
// output 1, 2, 3for (let key of map.values()) {
console.log(key);
}
// output one, two, threefor (let key of map.entries()) {
console.log(key);
}
// [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ]

One problem with Map object is you cannot map or filter over it.

let my_map = new Map([[ 1, 'one' ],[ 2, 'two' ],[ 3, 'three' ]]);let x = my_map.filter(([key, value]) => key > 1); // TypeError: my_map.filter is not a function

The solution is convert the map into an array of [key,value] pairs, filter the array and convert the result back to a map:

let my_map = new Map([[ 1, 'one' ],[ 2, 'two' ],[ 3, 'three' ]]);let new_map = new Map([...my_map]
.filter(([key, value]) => key > 1));
for (let key of new_map.values()) {
console.log(key);
}
// output two, three

WeakMap

A WeakMap is a Map where the keys are weak — in other words, if all references to the key are lost and there are no more references to the value it can be garbage collected, unlike Map (it is a very important point).

One problem with Map is the possibility of memory leak because the arrays ensure that references to each key and each value are maintained indefinitely. These references prevent the keys from being garbage collected, even if there are no other references to the object. This would also prevent the corresponding values from being garbage collected. MDN

WeakMap has the same API as Map, but one big difference: you cannot iterate over it, neither the keys, nor the values, nor the entries and you cannot clear a WeakMap, either.

You should ask why use this type of data structure. Let’s see:

  • Keeping private data about a specific object and only giving access to it through a reference to the Map.
  • Keeping data about library objects without changing them.
  • Keeping data about host objects like DOM nodes in the browser.

Let’s see a countdown example:

That’s all folks, in the next post I will talk about Set and WeakSet.

Thanks!

--

--