DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,673 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for A Complete Guide to Javascript Maps
Johnny Simpson
Johnny Simpson

Posted on • Originally published at fjolt.com

A Complete Guide to Javascript Maps

You're probably familiar with Javascript Objects - but did you know there is another way to create sets of data in Javascript, known as Maps? You might be using Javascript plain old objects right now, when a map may be a better solution to your problem.

Javascript maps differ in a few major ways to objects. Although typeof new Map() returns object, don't let that fool you! Here are some of the major differences from objects:

  • Does not contain any keys by default, unlike objects, which typically contain a prototype object unless created in a specific way.
  • They are guaranteed to be ordered by the order they were inserted. Objects are like this too these days, but they don't carry the same guarantee.
  • The keys of a map can be anything, including a function, or even an object. Whereas in Javascript, it must be a string or symbol.
  • They have better performance than objects on tasks which require rapid or frequent removal or addition of data.
  • They are iterable by default, unlike objects.

Given that maps have so many benefits, let's take a look at how they work.

The Basics of how Javascript Maps work

Any map in Javascript is initiated using the new Map() constructor. For example, let's create a map called myFirstMap:

let myFirstMap = new Map();
Enter fullscreen mode Exit fullscreen mode

The difference is to set, get, or delete keys from a map, you have to use specific methods that come along with Map. So to set a new value of someValue with the key firstKey, I can run the following method:

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');
Enter fullscreen mode Exit fullscreen mode

Deleting an item in a Javascript Map

If we then wanted to delete a key in a Javascript map, we have to call the delete() method:

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');
myFirstMap.delete('firstKey');
Enter fullscreen mode Exit fullscreen mode

You can also delete the entire map altogether, leaving no items in it using clear():

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');
myFirstMap.clear();
console.log(myFirstMap); // Returns Map(0)
Enter fullscreen mode Exit fullscreen mode

Getting a key in a Javascript Map

Similar in usage to the other methods, to get the value of firstKey, we have to use get():

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');

myFirstMap.get('firstKey') // 'someValue'
Enter fullscreen mode Exit fullscreen mode

Checking if a key exists in a Javascript Map

Javascript Maps also have a method called has(), if we want to check if a map has a certain key:

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');

myFirstMap.has('firstKey') // true
Enter fullscreen mode Exit fullscreen mode

Warning: don't use typical Object properties with Maps

Javascript is full of quirks, and maps are no different. Weirdly, maps can also support object notation. For example, this seems to work:

let myFirstMap = new Map();

myFirstMap['firstKey'] = 'someValue';

console.log(myFirstMap); // Map(0) { firstKey: 'someValue' }
Enter fullscreen mode Exit fullscreen mode

However, you should not do this! This is not creating new entries in the map itself - you're simply creating an object. So you'll lose all the benefits of Javascript maps.

Telling how big a Javascript Map is

One other useful thing where maps are a little easier to use than objects is finding out how many keys are in a map. For this, we can use the size() method, which returns the number of keys:

let myFirstMap = new Map();

myFirstMap.set('firstKey', 'someValue');

myFirstMap.size // 1
Enter fullscreen mode Exit fullscreen mode

For objects, we typically use a mixture of Object.keys() and length to find out the size of an object:

let myObj = { "name" : "John" };
let sizeOfObj = Object.keys(myObj).length; // 1
Enter fullscreen mode Exit fullscreen mode

Using Maps with non-string keys

As I mentioned, Javascript Maps allow non conventional keys, like functions and objects, whereas objects only allow strings and symbols. For example, this is valid in a map:

let myFirstMap = new Map();
let myFunction = function() { return "someReturn"; }
myFirstMap.set(myFunction, "value");
Enter fullscreen mode Exit fullscreen mode

Map keys are based on reference, not value. That means although the following will work:

let myFirstMap = new Map();
let myFunction = function() { return "someReturn"; }
myFirstMap.set(myFunction, "value");

myFirstMap.get(myFunction); // Returns "someReturn"
Enter fullscreen mode Exit fullscreen mode

This will not:

let myFirstMap = new Map();
let myFunction = function() { return "someReturn"; }
myFirstMap.set(myFunction, "value");

myFirstMap.get(function() { return "someReturn"; }); // Returns undefined
myFirstMap.get('someReturn'); // Returns undefined
Enter fullscreen mode Exit fullscreen mode

That's because although function() { return "someReturn"; } and myFunction are the same in value, they are not the same in terms of where they are stored in system memory. So they are not exactly equivalent. Similarly, maps do not work on return value - so myFirstMap.get('someReturn') also returns undefined.

The same example works for objects, with similar results:

let myFirstMap = new Map();
let myObject = { "someKey" : "someValue" }
myFirstMap.set(myObject, "value");

myFirstMap.get({ "someKey" : "someValue" }); // Returns undefined
myFirstMap.get(myObject); // Returns 'value'
Enter fullscreen mode Exit fullscreen mode

Merging Javascript Maps

If you have multiple maps you want to merge into one, you can merge them in the same way you merge objects - with the spread syntax. For example, here I merge myFirstMap and mySecondMap into myNewMap using the spread syntax:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
let mySecondMap = new Map();
mySecondMap.set("someOther", "value");

let myNewMap = new Map([...myFirstMap, ...mySecondMap]);

console.log(myNewMap);
// Map(2) { some: "value", someOther: "value" }
Enter fullscreen mode Exit fullscreen mode

Iterating on a Map

As mentioned, maps are iterable by default. If we want to iterate over objects we usually have to use a function like Object.keys. Ultimately this means we can use forEach on any map, like so:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");

myFirstMap.forEach(function(value, key, map) {
    // value -> the value of that key in the map
    // key -> the key for this item in the map
    // map -> the entire map
    console.log(value, key, map);
})
Enter fullscreen mode Exit fullscreen mode

Iterating on a Javascript Map using for

You can also iterate on a map using for(let ... of )! If you do that, each item is returned as an array of the key and value. For example:

let myFirstMap = new Map();
myFirstMap.set("some", "value");

for(let x of myFirstMap) {
    // Returns [ 'some', 'value' ]
    console.log(x);
}
Enter fullscreen mode Exit fullscreen mode

Iterating over values or keys in Javascript Maps

Another cool way we can iterate over values or keys in Javascript is to use the values() or entries() methods. These return a new iterator for the values and items in a map respectively. That means we can access the next key or value using next() functions, just like in generator functions.

For example, let's look at how entries() works:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");
myFirstMap.set("aFinal", "value");

let allKeys = myFirstMap.entries();
console.log(allKeys); // Returns MapIterator {} object

console.log(allKeys.next()); // Returns { value: [ 'some', 'value' ], done: false }
console.log(allKeys.next().value); // Returns [ 'some', 'value' ]
Enter fullscreen mode Exit fullscreen mode

Our return from allKeys.next() is an object. The value in this object is [ 'some', 'value' ] - an array of the first item in our map. We can keep running next() to get the following items in the map. Pretty cool! We can do the same thing again, with just values:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");
myFirstMap.set("aFinal", "value");

let allValues = myFirstMap.values();
console.log(allValues); // Returns MapIterator {} object

console.log(allValues.next()); // Returns { value: 'value' done: false }
console.log(allValues.next().value); // Returns 'value'
Enter fullscreen mode Exit fullscreen mode

Iterators like this prove useful in some specific situations, and can be a cool way to iterate through all the data in your Map.

Serialization of Maps in Javascript

One of the drawbacks for some people which maps have, is that they cannot be easily serialized with JSON.parse() and JSON.stringify. Trying to do so results in an empty object, and this kind of makes sense - since the object of a Map is empty, if we only populate it with entries:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");
myFirstMap.set("aFinal", "value");

// Returns {}
console.log(JSON.stringify(myFirstMap));
Enter fullscreen mode Exit fullscreen mode

The only realistic way to serialize a Map is to convert it to an object or array, which simply means you'll have to maintain some separate helper functions to do this task for you, should you use Maps. For example, we can use Array.from() to convert our Map to an array, and then use JSON.stringify() to serialize it:

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");
myFirstMap.set("aFinal", "value");

let arrayMap = Array.from(myFirstMap);

// Returns [["some","value"],["someOther","value"],["aFinal","value"]]
console.log(JSON.stringify(arrayMap));
Enter fullscreen mode Exit fullscreen mode

Then, if we want to turn it back into a map, we have to use JSON.parse() in conjunction with new Map():

let myFirstMap = new Map();
myFirstMap.set("some", "value");
myFirstMap.set("someOther", "value");
myFirstMap.set("aFinal", "value");

// Turn our map into an array
let arrayMap = Array.from(myFirstMap);

// The JSON stringed version of our map:
let stringifiedMap = JSON.stringify(arrayMap);

// Use new Map(JSON.parse...) to turn our stringed map into a map again:
let getMap = new Map(JSON.parse(stringifiedMap));

// Returns Map(3)Β {'some' => 'value', 'someOther' => 'value', 'aFinal' => 'value'}
console.log(getMap);
Enter fullscreen mode Exit fullscreen mode

Conclusion

Javascript Maps are a great way to store data, when you don't need all the flexibility of objects, and things like the order of your data are incredibly important. They also prove more performant than objects in situations requiring frequent addition and removal of items. In this guide we've covered everything you need to know about Maps, but if you want to learn more about Javascript click here.

Hope you've enjoyed this one - have a great day.

Top comments (3)

Collapse
 
jonrandy profile image
Jon Randy • Edited on

...unlike objects, which contain a prototype object.

Not quite correct - objects can be created without a prototype:

const emptyObj = {}   // Not really 'empty', has a prototype with all normal Object methods
console.log(emptyObj.__proto__)   // Object

const totallyEmptyObj = Object.create(null)   // has no methods, nothing
console.log(totallyEmptyObj.__proto__)   // undefined
Enter fullscreen mode Exit fullscreen mode
Collapse
 
smpnjn profile image
Johnny Simpson Author

yes correct, my language isn't exactly clear. Let me update.

Collapse
 
fruntend profile image
fruntend

Π‘ongratulations πŸ₯³! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 🫰

🀯

"I made 10x faster JSON.stringify() functions, even type safe"

☝️ Must read for JS devs