Map & WeakMap in JavaScript
By: Pavlo Savchuk
Tags: JavaScript, Coding, Programming

Photo by Christina Morillo: Pexels

Hi guys, how have you been? Today I’ll describe 2 data structures in JavaScript such as Map and WeakMap. I’ll describe what are they for and how I apply them. Let’s get started.

Map — is a collection of key/value pairs, just like an Object. The key difference is Map stores keys of any type (whereas Object stores keys as a String type).

Map methods and properties:

new Map([iterable]) – creates a new collection. The Map() receive an optional iterable object whose elements are key-value pairs.

– creates a new collection. The receive an optional iterable object whose elements are key-value pairs. map.set(key, value) – sets a value by the given key . The key may be of any type. This is important and will be demonstrated in the examples below.

– sets a by the given . The key may be of any type. This is important and will be demonstrated in the examples below. map.get(key) – returns the value by the specified key or undefined if the correspondent value is not present in the map.

– returns the value by the specified or if the correspondent value is not present in the map. map.has(key) – returns true if the key is in the collection, and false otherwise.

– returns if the is in the collection, and otherwise. map.delete(key) – deletes the element by the given key. Returns true if the element was deleted and false if the element was not in the collection.

– deletes the element by the given key. Returns if the element was deleted and if the element was not in the collection. map.clear() – cleans up the whole collection.

– cleans up the whole collection. map.size – returns the number of elements in the collection.

– returns the number of elements in the collection. forEach(callback[, thisArg]) – invokes a callback for each key-value pair in the map in the insertion order. The optional thisArg parameter sets the this value for each callback.

To loop through Map you have 3 methods to access data:

map.keys() – returns an iterable object of Map keys.

– returns an iterable object of Map keys. map.values() – returns an iterable object of Map values.

– returns an iterable object of Map values. map.entries() – returns an iterable object of [key, value] pairs. That would be the default for using in for..of the loop.

Why and when I use Map?

Performance. That’s the killer to me. Especially when dealing with the high loaded applications. The thing is how the map is saved in memory and when you need to access a specific item, it directly gives you the value stored in memory corresponded to that key. You can use an object as a key . E.g. whenever I need to save additional data to the user object, that does not need to be a part of a user object, I use Map. Whenever I need to save some meta-data for the entity — I use Map. In the past, I used to add a needed meta-data to the user object.

Examples

Let’s consider some samples:

const map = new Map(); map.set("0", "Lorem impsum"); // "0" as a key of a type

"string" map.set(0, "Hey!") // 0 as key with a type "number" map.set(true, "Example of having a boolean value as a key"); //boolean as a key. map.get(0) // "Hey!"

map.get("0") // "Lorem impsum"

/*Map stores key types so we have 2 separate values. If we had an object to save these values, object would convert keys into strings and we would have the same value for both "0" and 0 keys.*/ map.get(true) // "Example of having a boolean value as a key" /*Map can use objects as the keys*/

const user = { name: "Pavlo", .... }; /*Let's say we need to know the number of pages the user visited in our app. */ const numberOfPagesMap = new Map();

numberOfPagesMap.set(user, 12); numberOfPagesMap.get(user); // 12

If we try to switch Map to Object in the example above we would get the following:

const user = { name: "Pavlo", .... }; /*Let's say we need to know the number of pages the user visited in our app.*/ const numberOfPagesMap = {}; //declaring object

numberOfPagesMap[user] = 12; /*This is how JavaScript saved it:

numberOfPagesMap["[object Object]"] = 12;*/

Indeed, since user is an object in the example above, JavaScript converts key value to a string type and then saves it.

We also can chain set() method calls, since set() returns Map. Like below:

map.set("1", true).set(2,false).set({name:"John"}, {flag:true})

Map Looping

Note: looping through the Map happens in the same order in which elements were set in the Map. It is different from looping through Object, where keys are in sorted order.

/*Let's assume we are given a collection of employees in your town*/ const companyEmployeesMap = new Map([

["Samsung", 800 ],

["Panasonic", 120],

["Sony", 440],

["LG", 350],

]); // loop through keys

for (let company of companyEmployeesMap.keys()) {

console.log(company); // Samsung, Panasonic, Sony, LG

} // loop through values

for (let company of companyEmployeesMap.values()) {

console.log(company); // 800, 120, 440, 350

} // loop through elements via [key,value] pair

for ( const item of companyEmployeesMap){

console.log(item) // ["Samsung", 800 ] ...etc

} //that's the same as companyEmployeesMap.entries() // loop through elements with forEach

companyEmployeesMap.forEach((value, key, map) => {

console.log(`${key}: ${value}`); // Samsung: 800 .....

});

typeof & instanceof Map

Let’s say we have a contst userMetaDataMap = new Map(). This userMetaDataMap is an instance of the Map object.

typeof(userRoles); // "object"

userRoles instanceof Map; // true

Create a Map from an Object

Above, we have an example when we created a Map from the array of key-value pairs — companyEmployeesMap . If we intend to create a Map from the Object we may use Object.etnries a method like the below:

const companyEmployees ={

"Samsung": 800 ,

"Panasonic": 120,

"Sony": 440

}; const userMetaDataMap = new Map(Object.entries(companyEmployees));

The example above Object.entries() returns an array of key-value pairs that we use to create a new Map.

Create an Object from a Map

In case we want to create an Object from a Map we need to apply Object.fromEntries in conjunction with map.entries like below