JavaScript Map and Set
While working with JavaScript, developers waste a lot of time on choosing the right data structure.
Objects and Arrays are the primary data structures used to store collections of data. Objects are used for storing key/value pairs, and arrays- for indexed lists. To make developers’ life easier, ECMAScript 2015 represented two new kinds of iterable objects: Maps and Sets.
Maps ¶
A map is a key-value pairs collection that can apply any data type as a key, maintaining the sequence of its entries.
Maps contain both elements of objects and array. But, conceptually, they are similar to objects.
The primary distinction is that maps allow any type of keys.
The main properties and methods of maps are the following:
- new Map() – creating the map.
- map.set(key, value) – storing the value by the key.
- map.get(key) – returning the value by the key, undefined if no key exists in the map.
- map.has(key) – returning true if there exists a key, and false otherwise.
- map.delete(key) – removing the value by the key.
- map.clear() – removing everything from the map.
- map.size – returning the current element count.
So, you can use new Map() to create a map like this:
let map = new Map();
map.set('10', 'str'); // string key
map.set(10, 'num'); // numeric key
map.set(false, 'bool'); // boolean key
//Map can save the type, and a regular object can convert keys to a string,
//so these two values are different:
console.log(map.get(10)); // 'num'
console.log(map.get('10')); // 'str'
console.log(map.size); // 3
From this example, you can notice that they are not converted to strings, as any type of key is allowed.
Also, maps are capable of using objects as keys as demonstrated below:
let js = {
name: "Javascript"
};
// for each book, let's save the number of visits
let visitsCountMap = new Map();
// js is the key for the map
visitsCountMap.set(js, 250);
console.log(visitsCountMap.get(js)); // 250
One of the most significant map features is using objects as keys:
let js = {
name: "Javascript"
};
let visitsCountObj = {}; // try to use an object
visitsCountObj[js] = 250; // try to use js object as the key
console.log(visitsCountObj["[object Object]"]); // 250
In the example above, visitsCountObj is an object that converts all the keys like js to strings. So, the string key is "[object Object]". But, it is not completely right.
The SameValueZer algorithm is used for testing keys for equivalence. It is similar to ====. The only difference is that NaN is equal to NaN and can be applied as the key. You can’t change or customize this algorithm.
There is another option, too: the calls can be chained, as each map.set call returns the map, like this:
map.set('10', 'str')
.set(10, 'num')
.set(false, 'bool');
Iterating over Map ¶
Three main methods exist that allow looping over a map. They are as follows:
- map.keys() – returning an iterable for keys,
- map.values() – returning an iterable for values,
- map.entries() – returning an iterable for entries [key, value], it’s applied by default in for..of.
An example is as follows:
let priceMap = new Map([
['banana', 250],
['apple', 150],
['peach', 200]
]);
// iterate over keys (fruit)
for (let fruit of priceMap.keys()) {
console.log(fruit); // banana, apple, peach
}
// iterate over values (amounts)
for (let amount of priceMap.values()) {
console.log(amount); // 250, 150, 200
}
// iterate over [key, value] entries
for (let entry of priceMap) { // the same as of priceMap.entries()
console.log(entry); // banana, 250 (and so on)
}
Also, there exists a built-in forEach method, equivalent to Array:
let priceMap = new Map([
['banana', 250],
['apple', 150],
['peach', 200]
]);
// running the function for each pair (key, value)
priceMap.forEach((value, key, map) => {
console.log(`${key}: ${value}`); // banana, 250 etc
});
Using Object.entries ¶
Once a map is generated, an array can be passed with key/value pairs as follows:
// array of pairs [key, value]
let map = new Map([
['10', 'str'],
[10, 'num'],
[false, 'bool']
]);
console.log(map.get('10')); // str
A map can be created from an object as follows:
let obj = {
name: "Maria",
age: 20
};
let map = new Map(Object.entries(obj));
console.log(map.get('name')); // Maria
Object.fromEntries ¶
After learning how to create a map from a plain object using Object.entries(obj), let’s get to the opposite.
The Object.fromEntriesmethod allows performing the reverse process. Once you have an array of [key, value] pairs, it will generate a object from them like this:
let counts = Object.fromEntries([
['banana', 4],
['apple', 2],
['peach', 3]
]);
// now counts = { banana: 4, apple: 2, peach: 3 }
console.log(counts.apple); // 2
So, Object.fromEntries can be used for getting a plain object from the map. Once you store data inside a map, you should pass it to a third-party code, expecting a plain object, as demonstrated below:
let map = new Map();
map.set('banana', 4);
map.set('apple', 2);
map.set('peach', 3);
let obj = Object.fromEntries(map.entries()); //(*)
// obj = { banana: 4, apple: 2, peach: 3 }
console.log(obj.apple); // 2
The (*) line can be made shorter:
let obj = Object.fromEntries(map); // .entries()
Sets ¶
A set is a specific collection of “set of values” where every value can take place only once.
The primary methods used by set are shown below:
- new Set(iterable) – creating the set, and if an iterable object is supplied (usually an array), copying values from it to the set.
- set.add(value) – adding a value, returning the set itself.
- set.delete(value) – removing the value, returning true if the value is there at the moment of the calling, otherwise false.
- set.has(value) – returning true if the value is there inside the set, otherwise false.
- set.clear() – removing all from the set.
- set.size – counting the elements.
The set can be useful in various situations. For example, visitors are coming to your site, and you wish to remember all of them. Take into account that repeated visits must not lead to duplicates, and each visitor should be counted once. It can be easily done with Set like this:
let set = new Set();
let js = {
name: "Javascript"
};
let html = {
name: "Html"
};
let css = {
name: "Css"
};
// visits, some books come multiple times
set.add(js);
set.add(css);
set.add(html);
set.add(js);
set.add(css);
// set only stores unique values
console.log(set.size); // 3
for (let user of set) {
console.log(user.name); // Javascripr (then Css and Html)
}
let set = new Set();
let js = {
name: "Javascript"
};
let html = {
name: "Html"
};
let css = {
name: "Css"
};
// visits, some books come multiple times
set.add(js);
set.add(css);
set.add(html);
set.add(js);
set.add(css);
// set only stores unique values
console.log(set.size); // 3
for (let user of set) {
console.log(user.name); // Javascripr (then Css and Html)
}
Iterating over Set ¶
Looping over a set is possible either with for..of or with for..of like this:
let set = new Set(["bananas", "apples", "peaches"]);
for (let value of set) {
console.log(value);
}
set.forEach((value, valueAgain, set) => {
console.log(value);
});
Here is an interesting and a bit funny fact. The callback function that is passed inside forEach includes three arguments: a value, the same value valueAgain, and the target object. As you can see, the same value can appear in the arguments twice.
That can seem strange but helps in replacing the Map with Set in particular cases.
Summary ¶
In this chapter, we represented to you Map and Set. Now, let’s summarize what was covered in general. While Map is a collection of keyed values, Set represents a collection of unique values. Each of them has its methods and properties.
Both of these data structures add extra capabilities of JavaScript and can simplify common tasks (for example, detecting the length of a key/value pair collection or deleting duplicate items from a data set).
0 Comments
CAN FEEDBACK
Emoji