ES2015 introduced the new Map
and WeakMap
objects to JavaScript. They can be used as a key-value store, but unlike normal objects in JavaScript you can use objects as keys. Keys for normal objects ({}
) always have to be strings, and if you try to use an object it will be converted to a string ([object Object]
).
Using Maps
To assign values to a map you need to use the set
method:
(You’ll see later why I’m assigning obj
to window rather than using a local variable.)
Then, to retrieve the object call get
:
Difference between Map and WeakMap
The difference between Map and WeakMap lies in how the objects that are used as keys are treated during garbage collection.
Without the Maps, running delete window.obj
would remove the only reference to the obj
object, and the object would be removed from memory.
However, since obj
is used as a key in our Map
there still is a reference to obj
and it can’t be garbage collected.
WeakMap
s however are different: they act as if there was no additional reference to obj
. They only hold a weak reference to obj
, meaning that after running removing the obj
reference from the window object, obj
can be garbage collected.
Let’s change our code a bit to make obj
use up more memory:
If you run this in Chrome the memory consumption will rise by about 30MB. Here’s the screenshot from the DevTools memory profiler:
Now let’s try the same thing with a WeakMap
:
You can see from the heap snapshot that the memory used by obj
has been garbage collected:
Browser support for Map and WeakMap
The latest Chrome, Firefox, Edge and Safari support Map
and WeakMap
on desktop. There’s no support in IE10.
On mobile newer browsers also have support, but IE Mobile doesn’t.
A gotcha when trying this in the console
When I was playing around in the DevTools console I ran into some trouble, because memory wasn’t cleared up when I expected it to be.
It turned out that the problem was that the large object had been printed in the console, which caused Chrome to keep the object in memory.
The solution was to prevent obj
being logged in the console. In this case I’m just adding a meaningless 123;
statement that appears in the console instead: