📌 JavaScript

What is a JavaScript map? Difference b/w JS map & weakmap

January 03, 2022

A Javascript map object is a collection of key-value pairs where keys and objects can be of any data type including objects, functions, & primitive types, unlike the objects, created using {} should have only a string or a symbol as a key. The map data type was added in the EcmaScript version 6(ES6). 

To create a JS map, Map constructor is used. We can optionally pass an array of iterable objects to the Map to add the key-value pairs of that iterable object to the map.

const items = new Map([iterable]);

We can add key-value pairs to the map with the help of set method.

const person = new Map();
person.set('name', 'John');
person.set('age', 25);

console.log(person.size); // 2

A Map instance has got various methods for reading and manipulating the elements(key-value pairs) in it. It's an iterable and so by using iterative methods or loops we can read the data. 

The various methods that we can use on maps are:

  • set() - to add key-value pairs to the map
  • get() - to get the value of the key if it exists
  • has() - to check if the key exists in the map, returns a boolean
  • delete() - to delete the map element specified by the key
  • clear() - to clear/delete all the elements of the map
  • keys() - to get the iterator object of all keys in the map
  • values() - to get the iterator object of all values in the map
  • entries() - to get an iterator object with [key, value] elements 
  • forEach() - to call/invoke a callback function on every element in a map
  • size - to get the total number of elements in a map

Let's understand each method with examples

Javascript map methods

set() method

const items = new Map(); // Initializing empty map
const john = { name: 'John', age: 25};
items.set(john, 'person'); // object as a key
items.set(1, 'number'); // number as a key
items.set(true, 'boolean'); // boolean as a key
items.set('color', 'red');

console.log(items.size); // 4

We can see from the above that having any type of data type as the key is the specialty of javascript map objects. If it's a normal object then the keys get converted to strings or object strings.

As we know that the instance of Map returns an iterable, so we can use for-of loop to read the values of an iterable just like in JS sets

// Iterating from the previous map object
for(const item of items) {
// Logs:
// [{name: "John"}, "person"]
// [1, "number"]
// [true, "boolean"]
// ["color", "red"]

get() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);
letters.get('a'); // 1
letters.get(4); // d

has() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

// Checks if the key exists in the map element and returns a boolean
letters.has(5); // false
letters.has(4); // true

delete() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

// Deletes the map element if the given key exists
console.log(letters.size); // 3

clear() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

// Clears or deletes all the elements in the map
console.log(letters.size); // 0

keys() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

// map.key() method returns key of every map element
for(const key of letters.keys()) {
// Logs: a, b, 3, 4

values() method

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

// map.values() returns the value of each map element
for(const value of letters.values()) {
// Logs: 1, 2, c, d

entries() method

The  entries() method is similar to the Object.entries(), where it returns keys and values of an object as an array of [key, value] arrays. Similarly in the case of map entries() method, an iterator with [key, value] arrays is returned for every element in the map, instead of an array.

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

for(const letter of letters.entries()) {

// Logs: ["a", 1], ["b", 2], [3, "c"], [4, "d"]

forEach() method

The map forEach method works the same as the forEach method on arrays. It allows running a callback function on every element of the map. The first two arguments of the callback function gives value and key of the current element.   

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

letters.forEach((value, key) => console.log(key, value));
// Logs: a 1, b 2, 3 c, 4 d

size property

The size property of a Map instance returns the total number of elements(key-value pairs) present in the map, nothing but the length of the map. This property is not available on a normal object created using {}.

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

console.log(letters.size); // 4

So far we've seen different ways to iterate the map object. Let's see all together once.

Different ways to iterate maps

const letters = new Map([['a', 1], ['b', 2], [3, 'c'], [4, 'd']]);

for(const [key, value] of letters) console.log(key, value); 
for(const [key, value] of letters.entries()) console.log(key, value);
letters.forEach((value, key) => console.log(key, value)); 
// Above three iterations log the same result

for(const key of letters.keys()) console.log(key); // Logs: keys 
for(const value of letters.values()) console.log(value); // Logs: values

JS maps from JS objects

A JS map can be created from JS objects by converting them to arrays and vice versa.

// From object to map
const obj = {
  a: 1, 
  b: 2, 
  c: 3, 
  d: 4
const mapObj = new Map(Object.entries(obj));
for(const element of mapObj) console.log(element); 
// Logs: ["a", 1], ["b", 2], ["c", 3], ["d", 4]

// From map to object
const objFromMap = Object.fromEntries(mapObj);
// Logs: {a: 1, b: 2, c: 3, d: 4}

When and where to use JS map object?

A map is a collection of elements(key-value pairs) and the elements can be iterated in the order of their insertion.

A map can be used

1. To preserve the order of the key-value pairs

The order of the key-value pairs is not guaranteed in the object created using {} but javscript map object has definite order of the insertion of elements. 

2. To get good performance in frequent addition and removal of key-value pairs

Objects created using {} or Object are not optimized for frequent addition and deletion of key-value pairs. So in such cases using JS maps can give good performance.

There's a special case of JS maps called WeakMap, let's have a glimpse at it.

What is a weak map in Javascript?

A weakmap is similar to the map in Javascript but with limitations on the key data types and the methods, it can have.

Unlike map, weakmap can contain only the objects as keys and values can be of any data type. And only set(), get(), has(), delete() methods are available on a WeakMap instance. No iterative methods can be applied on weak maps, including, forEach etc.

const colors = new WeakMap();
const green = { name: 'green'};
const greenHex = { hex: '#00FF00'}
const red = { name: 'red'};
colors.set(green, greenHex);
colors.set(red, '#FF0000');
console.log(colors.has(red)); // true
console.log(colors.has(red)); // false

// Try adding a string key or any other data type except object to the weakmap
colors.set('blue', '#0000FF'); // Throws an error

A weakmap is called so because of the weak references to the data(objects) it contains. When the reference to the objects is lost, they get garbage collected.

let a = { index: 1 };
let b = { index: 2 };

const wMap = new WeakMap();

wMap.set(a, 'one');
wMap.set(b, 'two');
console.log(wMap.has(a)); // true
console.log(wMap.has(b)); // true
a = null; // removing the reference for { index: 1 } 
console.log(wMap.has(a)); // false

WeakMap, similar to WeakSet is mainly used as additional storage of data for objects that are stored or managed from another location. 

That was a quick look at weak maps and overall the maps in Javascript.

If you like receiving regular tips, tricks related to web development and technology then do follow on devapt-twitter @dev_apt