How JavaScript works: understanding Maps and their use cases + 4 advantages compared to Objects

Ukpai Ugochi
SessionStack Blog
Published in
13 min readJan 7, 2022

This is post # 57 of the series, dedicated to exploring JavaScript and its building components. In the process of identifying and describing the core elements, we also share some rules of thumb we use when building SessionStack, a JavaScript tool for developers to identify, visualize, and reproduce web app bugs through pixel-perfect session replay.

Objects in JavaScript are entities with properties and methods and they can be used for representing properties as they are being stored in key-value pairs.

Although representing properties using Objects is a reasonable approach, there are also some shortcomings associated with it. This is where the use of Maps comes in. There are so many features that the Map offers that you may not find in plain Objects.

For instance, you can iterate through the elements in a Map and still maintain the insertion order. Also, you can use functions, Objects, or any other primitive data types as keys in a Map.

In this article, we’ll explore Maps and talk about Map features and compare them with Objects. Also, I’ll drop some useful tips on how to use Maps and gain effective results.

Map instance

Map is a collection of elements using the key-value pair format, just as in Objects. It can hold Objects as either key or value.

Maps were introduced in JavaScript in ES6. In order to create a Map instance, you have to make use of a Map() constructor alongside the new keyword, like this:

From the above example, we just created a Map instance and called it staff. We also passed in first name and second name as the key elements that will hold the elements Ukpai and Hannah as their respective values. If we check this out on the console with console.log, we’ll get an output like this:

Where the arrows indicate which key holds what value.

Properties of Map instance

Maps also have properties. These properties are used when you want to check specific information like the size of the Map.

In this section, I am going to talk about the Map.size property.

Map.size

To access the number of items in a Map, use the .size accessor property, which will return an integer, representing the number of elements found in the Map.

When we run the example above we’ll get 2 on the console.

For instance, if we add another set of key-value pairs of entries, say age (key) and 23 (value), the map.size property will return 3.

Next up we are going to talk about performing operations on Map entries using Map instance methods.

Map instance methods

These Methods can perform certain operations like deleting a particular set of key-value pair entries from a Map.

In a Map, you can also add a new set of entries or check for keys present in it.

For instance, if we want to check for the keys in a Map, we can simply do that by running the code below:

This example utilizes the map.keys() method. If we check this out in the console we’ll get first-name and second-name like this:

Where first-name and second-name are the keys. You can do a bunch of other things with Maps

Map.set()

In Maps, you can add a new set of entries (key-value pair) at any point in your program. Let’s say we want to add an age entry into the Map. Although we can do so by manually adding it into the Map, what happens if we have a large codebase and we want to dynamically add entries that are not known in advance?

This means we’ll need to constantly update the Map. This may end up becoming a difficult and challenging task. To solve this issue, we can make use of the .set() method.

Now, if you check this out on the console, you will get an output like this

Notice that the key-value pair of age and 23 was added to the Map object. Also, notice how the size has changed from 2 to 3. This is because we have just updated the Map. So, the .set() method adds a new set of entries to the Map.

The .set() method accepts two parameters. The first parameter which denotes a key and the second parameter which denotes a value. Using only one parameter in the .set() method will cause it to treat that parameter as a key and pass an undefined value into it. This is illustrated in the example below:

From the example above notice that we used only one parameter ‘Paul’. So, if we run this in the console, we’ll see something like this:

Also, you can update (modify) an element inside a Map using the .set() method.

For instance, if you want to change the value of the second-name which is currently Hannah into something else like Doe, well you can do that using the .set() method.

Example:

So, if you check this out on the console, you should notice that the value Hannah has just been replaced with Doe.

Map.delete()

Sometimes you might want to delete an entire set of entries from a Map. Let’s say we have a third element (age and 23), but now we no longer want it. You can use the map.delete() method like this:

Now, instead of having, first-name, second-name, and age on the console, you only get first-name and second-name. This is because you have successfully removed the key age and it’s value 23 from the list of entries.

Note that the .delete() method only accepts one parameter which is the key of the entry you intend to remove. Let’s look at the example below:

This won’t work because 23 is not a key but a value.

Map.clear()

Let’s see what happens if we want to remove all entries in the Map, not just a specific entry. Although we can decide to delete each entry one after the other using the .delete() method, this will be effective, but complex.

Therefore, in order to have an effective and faster removal of all the entries, you should make use of the .clear() method. The .clear() method removes entries from the Map just like the .delete() method. It removes all the entries in the Map object and not just a specified entry.

For instance, let’s say we don’t want the elements inside our Map and so we want to empty it. We can do this with the .clear() method like this:

The example above will empty the Map and return a size of 0 for the Map Object on the console. Note that we don’t need to pass in any parameter into the .clear() method as we’re not expected to make any specifications. The only specification we’ll need is the name of the Map.

Map.get()

The Map also allows us to check for specific values. One of the ways you can check for entries in a Map is by using the .get() method. The .get() method returns the value associated with a specified key:

From the example above, the expected output is the value associated with the key first-name which in our case happens to be Ukpai.

The .get( ) method accepts only one parameter, which is expected to be a key in the Map. Therefore, if you pass in a parameter that is not a key in the Map, you will get undefined in the console. Also, if you pass two or more parameters in the .get() method, only the first parameter will be used.

Map.keys()

Just as we can check for the values associated with keys in a Map, it is also possible to check for the keys of each entry in a Map. To do this you need to make use of the .keys() method:

if you check this out on the console, you will see a list of all the keys (i.e. first-name, second-name, and age), associated with each entry in the Map. We don’t need to pass in any parameter into the .keys( ) method.

Map.values()

Earlier we explored how to get values associated with a specified key in a Map. However, in some cases, you might want to get all the values in the Map. In this case, the .get() method won’t be very helpful.

Therefore, in order to get all the values in a Map, we’ll need to make use of the .values() method. The .values() method returns an Object that contains the values of each entry in the Map in the order in which they were inserted inside the Map.

The example above will return Ukpai, Hannah and 23 in the console. This method doesn’t require you to pass any parameter into it.

Map.entries()

So far, we have explored how to check for keys and values of entries in a Map as single entities. However, you can also get a result of both the keys and values as a single pair, using the .entries() method.

The .entries() method returns an Object that contains a key-value pair list for each entry:

If you run the above example properly, you will get an output that contains each of the key-value pair entries in the Map Object. Your output should look similar to this:

Note that the .entries() method is another method that does not require the passing of parameters.

Map.forEach()

The forEach() method is used when iterating through the list of items in the Maps. Let’s say we want to print out the entries in a Map. But this time, we don’t want the normal pattern of using arrows to connect keys and values, we want to do so using a function.

You can apply this function to each key/value pair in the Map Object using the forEach() method like this:

So, the forEach() method executes the provided callback (function) once for each key in the Map.

Comparing Maps and Objects

Maps and Objects are quite similar in terms of creating and passing values into them. For example, both Maps and Objects allow you to work with key-value pair elements. Also, you can perform property checks and carry out operations like deleting, retrieving, and modifying keys and values. For this reason, Objects have been used as Maps in earlier times.

But regardless of these similarities, there are still some key differences between a Map and an Object and I am going to list and talk about them in this section:

Default keys

By default, a Map does not contain any keys. What you can find inside a Map is what you put into it. But an Object contains some default keys that could collide with the ones you insert into it if you are not careful enough.

Keys Datatype

As I mentioned earlier in this article a Map can contain keys of any data type, it could be Objects functions or arrays. But in Objects, the key must always be a string or a symbol.

Iteration

Maps are also iterable, so you can easily iterate through the entries in a Map using the forEach( ) method, just as we did before, whereas Objects do not support the iteration protocol, so it could be difficult to directly iterate Objects.

Size

Checking the number of entries in a Map is quite easy compared to checking that of Objects. Checking the number of entries in a Map can be done using the .size accessor property. But if you wish to check the number of items in an Object you will be required to do so manually.

So, these are the few key differences and similarities between a Map and an Object. These differences make them unique and specific for different types of tasks.

Next up I am going to show you some good practices you should adhere to when using the Map data type.

Best practices on using Map

Setting properties

You can add Object properties to a Map using new Map.

However, this is not a good practice, as doing so will cause other operations to fail. This is because this method of setting data doesn’t interact with the map structures, it uses the generic object feature. Therefore, although the console prints Ukpai, the methods below will fail.

The best way of passing and storing data in a Map is through the use of the .set() method, which we discussed earlier.

Case sensitivity

Always remember that both keywords and identifiers in a Map are case-sensitive. For instance, in creating a Map instance, you are expected to use an uppercase M. If you use a lowercase m, you will receive an uncaught reference error.

Simplicity over complexity

Always remember that a simple but effective code is more appreciated than a complex one. So, while coding you need to pick the right methods that best suit the task at hand.

Code readability

Always remember that what makes your code good is not just the ability for it to complete the task at hand, but also how readable it is. So, while working with Maps try as much as possible to make the code readable, make it less complex and less bulky. For instance in a case where you want to erase all entries in the Map, always choose the .clear( ) method over the .delete( ) method, that will make your work less bulky.

Conclusion

The use of Map in JavaScript could be very helpful, as it makes writing programs more efficient. In order to properly use a Map and get the effective result, you have to properly understand key concepts and methods.

You have to be very careful about the data structures you pick for certain tasks, especially for ones that could potentially degrade the performance of your product. Even if you feel like the proper decisions have been made, it’s always necessary to verify that this is indeed true and your users have a great experience with your product.

A solution like SessionStack will allow you to replay customer journeys as videos, showing you how your customers actually experience your product. You can quickly determine whether your product is performing according to their expectations or not. In case you see that something is wrong, you can explore all of the technical details from the user’s browser such as the network, debug information, and everything about their environment so that you can easily understand the problem and resolve it.

There is a free trial if you’d like to give SessionStack a try.

SessionStack replaying a session

If you missed the previous chapters of the series, you can find them here:

--

--