In the past, JavaScript was limited when it came to collections. While other languages offer lists, sets, associative maps, and dictionaries, JavaScript only offered only arrays. JavaScript programmers had to come up with workaround for creating sets or maps, which made the code hard to maintain.
Now, with ES6, JavaScript offers new built-in classes for sets and maps that make programming far easier to maintain. In this tutorial, we will introduce you to map and set in detail along with code examples, use cases, and hands-on exercises. This tutorial is ideal for JavaScript developers who want to modernize their JavaScript skills.
This tutorial at a glance:
map
?map
set
?set
map
Get up to speed on modern JavaScript
This course covers the modern JavaScript features, including ECMAScript 2015 (ES6), 2016 (ES7), and 2017 (ES8). By the end, you’ll be able to add new features and write code more efficiently.
Rediscovering JavaScript: ES6, ES7 & ES8
Prior to ES6, JavaScript developers used objects to map keys to values. However, using an object as a map has its limitations. For example:
keys()
method converts fields to strings, which leads to collision of keys.ES6 introduced some new built-in classes, including a collection type called Map
, which can hold key-value pairs of any type. Unlike the object approach, the new Map object can remember key insertion order.
In simple terms, a JavaScript Map
is an associative collection of distinct keys and values. Both keys and values can be any primitive or object. This is a significant data structure with many valuable uses.
Note: A
WeakMap
is similar to a Map but all keys of aWeakMap
are objects.
To create a new Map
, we use the following syntax:
let map = new Map([iterable]);
Let’s put this into practice with a more complex example. Below we have a Map that holds names as keys and scores as values.
'use strict';//START:DEFINEconst scores =new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);scores.set('Jake', 14);console.log(scores.size);//END:DEFINE
scores
Map has been initialized with names and scores. The initial data may be any iterable with a pair of keys and values.set()
method (line 7)Note:
Map.has(key)
above will return the Boolean value to indicate if the element associated with a specified key is in the map
Once we know how to create maps with JavaScript, there are a lot of things we can do with them.
First, let’s learn about iteration through maps. There are 3 methods we can use:
map.keys()
: returns an iterable for keysmap.entries()
: returns an iterable for entries [key, value]
map.values()
: returns an iterable for valuesWe can iterate over the collection of keys and values with the entries()
method, which returns an iterable, so we can use the enhanced for loop
along with destructuring.
For example, below, we extract the name and score for each key-value pair:
'use strict';//START:DEFINEconst scores =new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);scores.set('Jake', 14);//END:DEFINEfor(const [name, score] of scores.entries()) {console.log(`${name} : ${score}`);}
We can also use the forEach
method, which is an internal iterator.
'use strict';//START:DEFINEconst scores =new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);scores.set('Jake', 14);//END:DEFINEscores.forEach((score, name) => console.log(`${name} : ${score}`));
The first parameter that the function receives is the value for a key that appears as the second parameter. The same forEach()
method can be used to iterate over only the values:
'use strict';//START:DEFINEconst scores =new Map([['Sara', 12], ['Bob', 11], ['Jill', 15], ['Bruce', 14]]);scores.set('Jake', 14);//END:DEFINEscores.forEach(score => console.log(score));
If you receive only one parameter, it will be the value, and if you receive two parameters, then it will stand for the value and key for each key-value pair.
You can also pass an iterable object to the Map()
constructor:
let userRoles = new Map([[sarah, 'admin'],[bob, 'editor'],[jill, 'subscriber']]);
We can get an elements from a map by key with the get()
method:
But if you pass a key that is not in that map, the it will return undefined.
userRoles.get(sarah); // admin
But if you pass a key that is not in that map, the it will return undefined.
let foo = {name: 'Foo'};
userRoles.get(foo); //undefined
We can use the size
property to get the number of elements in our maps.
console.log(userRoles.size); // 3
At times, you may want to work with an array instead of an iterable object. We can use the spread operator to convert keys for each element into a new array.
var keys = [...userRoles.keys()];
console.log(keys);
This piece of code will convert the values of elements to an array:
var roles = [...userRoles.values()];
console.log(roles);
clear()
: removes elements from the map object.map.set(key, value)
: stores the value by the keydelete(key)
: removes a specific element (as specified by the key)set(key, value)
: sets the value for the key and returns the map object. Can be chained with other methods.forEach(callback[, thisArg])
: invokes a callback for each key-value pair in insertion order. The thisArg
parameter is optional and sets the this
value for each callback.has(key)
: returns true
if a value associated with the key exists, otherwise, false
. keys()
: returns a new iterator with the keys for elements in insertion order.values()
: returns a new iterator object with the values for each element in insertion order.map.size
: returns the current element countSet
is another new collection introduced by ES6. The Array
class of JavaScript can work with ordered collection of data, but not so well with unordered collections or when values held in the collection are unique. That’s why JavaScript introduced Set
.
A set
is a unique collection of primitives and objects, and duplicates are not allowed. We can either create an empty set and add objects, or we can initialize a set with the contents of an iterable (like an array).
Let’s explore this with an example. Below, we have a set of names with five values. One of the values is not included in the set due to duplication.
'use strict';//START:CREATEconst names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']);//END:CREATE//START:SIZEconsole.log(names.size);//END:SIZE
We can add elements to an existing set, like below:
names.add('Matt');
The add()
method returns the current Set
, which is useful for chain operations, such as more calls to add()
or other methods of Set
:
names.add('Kate')
.add('Kara');
This course covers the modern JavaScript features, including ECMAScript 2015 (ES6), 2016 (ES7), and 2017 (ES8). By the end, you’ll be able to add new features and write code more efficiently. Educative’s text-based courses are easy to skim and feature live coding environments, making learning quick and efficient.
Once we figure out how to create sets, it’s easy to work with them. First, let’s look at the built-in functions for sets:
has()
: to check if a set has a particular element.clear()
: to empty an existing set or remove an existing element using the delete()
method.keys()
: to get all the values from a Setentries()
: to iterate over a Set using the enhanced for loop, like below:'use strict';//START:CREATEconst names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']);//END:CREATE//START:ADDnames.add('Mike');//END:ADD//START:ADD2names.add('Kate').add('Kara');//END:ADD2console.log(names.has('Brad'));console.log(names.entries());console.log(names.keys());console.log(names.values());//START:ITERATE1for(const name of names) {console.log(name);}//END:ITERATE1
Set does not yet offer methods like filter()
and map()
, but we can create an array from the set and use a functional style methods on that new array.
For example, below we use methods filter()
, map()
, and forEach()
to pick only names that start with J
and then transform them to uppercase.
'use strict';//START:CREATEconst names = new Set(['Jack', 'Jill', 'Jake', 'Jack', 'Sara']);//END:CREATE//START:ADDnames.add('Mike');//END:ADD//START:ADD2names.add('Kate').add('Kara');//END:ADD2//START:FILTER[...names].filter(name => name.startsWith('J')).map(name => name.toUpperCase()).forEach(name => console.log(name));//END:FILTER
Use the size
property of the Set object to return its size.
let size = chars.size;
console.log(size);// 3
To remove an element from a set, use the delete()
method.
chars.delete('f');
console.log(chars); // Set {"a", "b", "c", "d", "e"}
And to delete all elements of a set, use the clear()
method:
chars.clear();
console.log(chars); // Set{}
To invoke a callback on every element of your set, use the forEach()
method.
roles.forEach(role => console.log(role.toUpperCase()));
new Set(iterable)
: creates a set.set.add(value)
: adds a given value and returns the setset.has(value)
: returns true
if a value exists in the set, otherwise, returns false
.set.clear()
: removes everything from a setTo solidify your learning, let’s do a hands-on exercise with map in JavaScript. Use Map
to get the desired output as given below. When creating an object of createTodo()
, it should return a map element.
Input calls | Output |
---|---|
console.log(todo.get('learn JavaScript')); |
done |
console.log(todo.get('write elegant code')); |
work-in-progress |
console.log(todo.get('automate tests')); |
work-in-progress |
console.log(completedCount(todo)); |
1 |
The solution to this challenge is given below. Try it yourself first.
'use strict';const createTodo = function() {const todo = new Map();return todo;};const completedCount = function(map) {return;};const todo = createTodo(); //Returns a Map
Start by creating a map element. The Map
object todo
is created on line 4 using the built-in class. You can see that the map object, todo
is calling Map.get()
with different keys to get their values. This means that we need to add all the keys and values.
We add the new element in todo
with the keys and associated values. On lines 5-7, we add the new elements by setting values for the keys.
For completedCount()
, we define a new function with a map object parameter. The function will return the count of tasks that are completed. So, essentially, we are filtering all the values of elements in the map object to get the elements with the value equal to done
(see line 14).
On line 15, the length property is used to get the count of the special elements.
Map and set are valuable additions to JavaScript, and they will make your code cleaner and easier to maintain. Now that you have a solid understanding of map and set, you’re ready to tackle other features added in ES6 and beyond.
Some concepts to cover next to modernize your JavaScript are:
To get up to speed on JavaScript’s features, check out Educative’s course Rediscovering JavaScript: ES6, ES7 & ES8. This course covers the modern JavaScript features to make your code elegant, concise, expressive, and less error prone. You will start by learning the basic features of modern JavaScript, and in the second half, you will dive deep into complex features, like destructuring, literals, inheritance, modules, promises, and metaprogramming.
By the end of this course, you will be able to add new features with minimum effort and write code more efficiently!
Happy learning!
Free Resources