DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป is a community of 964,423 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Weakmap in javascript
Code Oz
Code Oz

Posted on • Updated on

Weakmap in javascript

Let's remember on Garbage Collector !

let obj = { name: 'toto' }

// The object { name: 'toto' } can be accessed
// since obj has the reference to it

// overwrite the reference
obj = null

// the object will be removed from the memory
// since we have lost all reference on it
Enter fullscreen mode Exit fullscreen mode

Another exemple,

let obj = { name: 'toto' }
let arr = [ obj ]

obj = null
Enter fullscreen mode Exit fullscreen mode

In this exemple, the object { name: 'toto' } will not be removed since the array keep reference on it !

What is the difference between strong and weak reference ?

In fact, most variables in javascript keep a Strong reference on an object. For example the array above keeps a strong reference on the object ({ name: โ€˜totoโ€™ }).

If any variable keeps strong reference on the object, the object will not be a garbage collector, but if there are only variables that keep weak reference on the object, it will be removed by garbage collector.

Some variable types have a weak reference on an object, this is the case for Weakmap.

Weakmap

A weakmap is an additional data storage, it can allow us to extend an object from outside (third party lib) or sealed object without inferring garbage collector ! Or create a cache function smartly !

Donโ€™t panic I will explain and show what it means ! Before we will compare map and weakmap.

Map vs Weakmap

With map the object occupies memory and may not be garbage collected. Map has strong reference on objet.

let obj = { name: 'toto' }
let mapObj = new Map()
mapObj.set(obj, 'any value')

obj = null
mapObj.size() // 1
Enter fullscreen mode Exit fullscreen mode

Weakmap is totally different, it doesnโ€™t prevent garbage-collection of key objects.

First rule, weakmap accepts only object as key, secondly it keeps only weak reference on object.

let obj = { name: 'toto' }
let weakmapObj = new WeakMap()
weakmapObj.set(obj, 'any value')

obj = null
weakmapObj .size() // 0
Enter fullscreen mode Exit fullscreen mode

Object is removed by garbage collector since weakmap has only weak reference on the object { name: โ€˜totoโ€™ } and this object has no longer strong reference ! (only the variable obj has keep reference on it)

When use this ?

As you can see, Weakmap is strong (yes it's a joke) but it can be use everytime, it can be used in a few situation.

Cache Function

const cache = new WeakMap() 

const process = function (obj) { 
    // If the input is not already cached 
    if (!cache.has(obj)) { 
        // Imagine a function that need a lot of memory/ressource 
        // We don't want to re-execute bigOperation function
        // if the input is the same ! 
        const result = bigOperation(obj) 
        // So we execute the function one time and
        // we store the result in cache ! 
        cache.set(obj, result) 
    } 
    return cache.get(obj) 
} 

let obj = { /* any object */ } 
// first time we don't have this input as cache, so we will put into 
const firstResult = process(obj) 
// second time we don't need to execute the big function, 
// just need to exctract the result in cache 
const secondeResult = process(obj) 
// the original object will be removed from weakmap ! 
obj = null 
Enter fullscreen mode Exit fullscreen mode

With a map, this cache function should have kept obj in memory !
It can lead to memory leaks !

Leak memory can be created when we keep reference on an unused object, so if you donโ€™t use any more objects, remove any variable reference on it !

โš ๏ธ We cannot use .keys() / .values() / .entries() with weakmap since we donโ€™t know when the garbage collector will remove the object !

Last exemple

Counter of visits dynamic without leak memory

// Counter of visits
let visitsCountMap = new WeakMap()

// increase the visits count
function countUser(user) {
  const count = visitsCountMap.get(user) || 0
  visitsCountMap.set(user, count + 1)
}

let toto = { name: "toto" }

countUser(toto) // count his visits

// later toto leaves us
toto = null
Enter fullscreen mode Exit fullscreen mode

Note: this article is inspired by https://javascript.info/weakmap-weakset


I hope you like this reading!

๐ŸŽ You can get my new book Underrated skills in javascript, make the difference for FREE if you follow me on Twitter and MP me ๐Ÿ˜

Or get it HERE

๐ŸŽ MY NEWSLETTER

โ˜•๏ธ You can SUPPORT MY WORKS ๐Ÿ™

๐Ÿƒโ€โ™‚๏ธ You can follow me on ๐Ÿ‘‡

๐Ÿ•Š Twitter : https://twitter.com/code__oz

๐Ÿ‘จโ€๐Ÿ’ป Github: https://github.com/Code-Oz

And you can mark ๐Ÿ”– this article!

Top comments (4)

Collapse
 
adam_cyclones profile image
Adam Crockett

Hmm this is really interesting, about the cache function is this faster in a worth while way. I'm trying to understand if weakmap is worth investing time into. I can see it could save memory with the proper usage. But I was under the impression that you cannot invoke and are not garenteed to have GCed what you wanted cleaned up.

Collapse
 
raddevus profile image
raddevus • Edited on

Right, GC is non-deterministic (you don't know when it will fire) and you can't call GC yourself, but using WeakMap would at least provide a way that the GC will (eventually) collect these WeakMap items. The difference being that with the regular Map items they may never be GC and so will stay in memory until your program is unloaded. Just my take on it. It's an interesting article.

Collapse
 
adam_cyclones profile image
Adam Crockett

Gotcha yes that's what I got from this too. Thanks for confirming that.

Collapse
 
codeoz profile image
Code Oz Author

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

โญ๏ธ๐ŸŽ€ JavaScript Visualized: Promises & Async/Await

async await