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 mapget()
- to get the value of the key if it existshas()
- to check if the key exists in the map, returns a booleandelete()
- to delete the map element specified by the keyclear()
- to clear/delete all the elements of the mapkeys()
- to get the iterator object of all keys in the mapvalues()
- to get the iterator object of all values in the mapentries()
- to get an iterator object with [key, value] elementsforEach()
- to call/invoke a callback function on every element in a mapsize
- 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) {
console.log(item);
}
// 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
letters.delete('b');
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
letters.clear();
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()) {
console.log(key);
}
// 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()) {
console.log(value);
}
// 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()) {
console.log(letter);
}
// 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);
console.log(objFromMap);
// 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
colors.delete(red);
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.