How to use JavaScript Collection with Map

How to use JavaScript Collection with Map

Introduction

Unlike many other programming languages, JavaScript's way of handling data collection is mostly with objects and arrays(don't forget, technically array is also a type of object in JavaScript). A majority of the developers rely on these heavily for slicing and dicing the data into a suitable data structure.

In the pre-ES6 era, there were not many options to deal with collections of data. Using an array was a great way of achieving it. The combination of an array and object makes the data collection useful. But, there are some shortcomings with this:

  • The key of an Object can only be of type string.
  • The Object doesn't have a few important properties like knowing the size of it, or the flexibility of iterating through it.
  • The Object doesn't maintain the order of the elements in it.

ES6(ECMAScript 2015) brought us two new data structures, Map and Set to make the data collection more flexible and useful. In this article, we will go over the Map data structure to learn how to use it in practice.

An explanation of the Set data structure will follow as a future article post.

Maps

A Map is a collection of key-value pairs where the key can be of any type. The Map remembers the original insertion order of the elements. It means the data from the Map will be retrieved in the same order that it was inserted.

If you notice closely, Map has characteristics of both Object and Array.

  • Object characteristic - Supports the key-value pair structure.
  • Array characteristic - Remembers the insertion order.

Create and Initialize a Map

A new Map can be created as,

const map = new Map();

It returns an empty Map.

Map(0) {}

A point to note here. A newly created Map has no default keys. Whereas, if you create a JavaScript object to make it work like a Map, it would inherit properties from its prototype.

Another way of creating a Map is with initial values. Here we are creating a Map initializing with three key-value pairs,

const greenrootsBlog = new Map([
        ['name', 'greenroots'],
        ['type', 'blog'],
        ['writer', 'Tapas Adhikary'],
    ]);

It returns a Map with three elements,

Map(3)
{
   "name" => "greenroots", 
   "type" => "blog", 
   "writer" => "Tapas Adhikary"
}

Add values to the Map

To add value to a Map, use the set(key, value) method. The set(key, value) method takes two parameters, key and value, where the key and value can be of any type, primitives(boolean, string, number etc) or an object.

// create a map
const map = new Map();

// Add values to the map
map.set('name', 'greenroots');
map.set('type', 'blog');
map.set('writer', 'Tapas Adhikary');

Output,

Map(3)
{
   "name" => "greenroots", 
   "type" => "blog", 
   "writer" => "Tapas Adhikary"
}

Please note, if you use the same key to add values multiple times to a Map, it will always replace the last value.

// Add a different writer
map.set('writer', 'Someone else!');

Now the map output will be,

Map(3)
{
   "name" => "greenroots", 
   "type" => "blog", 
   "writer" => "Someone else!"
}

Getting values from the Map

You must have guessed it by now. Yeah, Map has a method called, get(key) for getting value from it by passing a key.

map.get('name');
map.get('type');
map.get('writer');

Please note, the get(key) method returns an undefined if a non-existing key is passed to it.

Map Keys

A prominent difference of an object and the Map is, Map keys can be of any type. Let us see it with examples.

// create a Map
const funMap = new Map();

funMap.set(360, 'My House Number'); // number key
funMap.set(true, 'I write blogs!'); // boolean key

let obj = {'name': 'tapas'}
funMap.set(obj, true); // object as key

console.log(funMap);

Output,

Map(3) 
{
  360 => "My House Number", 
  true => "I write blogs!", 
  {…} => true
}

Now,

funMap.get(360); // returns, 'My House Number'
funMap.get(obj); // returns, true
funMap.get('360'); // undefined

A regular JavaScript object always treats the keys as strings. Even when you pass them as other primitives or objects, it internally converts the keys to strings. Here is an example to understand it,

// Create an empty object
const funObj = {};

// add a property. Note, passing the key as a number.
funObj[360] = 'My House Number';

// It returns true.
// Because the number 360 got converted to a string '360' internally!
console.log(funObj[360] === funObj['360']);

Map properties and methods

The Map has built-in properties and methods that make it so powerful and flexible to use. Let's create a Map to explain them.

const map = new Map();

map.set('John', 34);
map.set('Alex', 15);
map.set('Buddy', 37);

Know the size of a Map

Use the size property of the Map to know how many elements are in it.

console.log('size of the map is', map.size);

It reruns the number of elements in a Map. In this case, it will be 3.

Please note: Just like array's length, size is also a property, not a method.

Find an element with has()

The method has(key) returns true if the Map has an element with the key.

console.log(map.has('John')); // returns, true

console.log(map.has('Tapas')); // returns, false

Remove an element with, delete()

We can delete an element from the map using the delete(key) method.

map.delete('Buddy'); // removes the element with key, 'Buddy'.

Clear the entire Map

Use the clear() method to remove all the elements at once from the Map.

// Clear the map by removing all the elements
map.clear(); 

map.size // It will return, 0

MapIterator - Keys(), values(), entries()

All the methods(except clear()) we have seen so far, is to deal with the key-value of a Map one-by-one. There are three useful methods to get all the keys, values, and key-value pairs respectively.

These methods return a MapIterator which is excellent because you can do a for-of or forEach loop directly on it.

First, create a Map,

const ageMap = new Map([
        ['Jack', 20],
        ['Alan', 34],
        ['Bill', 10],
        ['Sam', 9]
]);

Get all the keys

console.log(ageMap.keys());

Output,

MapIterator {"Jack", "Alan", "Bill", "Sam"}

Get all the values

console.log(ageMap.values());

Output,

MapIterator {20, 34, 10, 9}

Get all the entries(key-value pairs)

console.log(ageMap.entries());

Output,

MapIterator {"Jack" => 20, "Alan" => 34, "Bill" => 10, "Sam" => 9}

Iterating over a Map

There are multiple ways of iterating over a Map. You can use, forEach or for-of loop to iterate over it.

With forEach

 // with forEach
 ageMap.forEach((value, key) => {
   console.log(`${key} is ${value} years old!`);
 });

Note, the first argument is the value and the second is the key. The output is,

Jack is 20 years old!
Alan is 34 years old!
Bill is 10 years old!
Sam is 9 years old!

With for-of

We can simply destructure the keys and values from the Map using the for-of loop.

for(const [key, value] of ageMap) {
  console.log(`${key} is ${value} years old!`);
}

Object to Map

You may encounter a situation where you need to convert an object to a Map like structure. You can use the method, entries of Object to do that.

const address = {
        'Tapas': 'Bangalore',
        'James': 'Huston',
        'Selva': 'Srilanka'
};

const addressMap = Object.entries(address);

Map to Object

If you want to do the reverse, you can use the method called, fromEntries.

Object.fromEntries(map)

Map to Array

There are a couple of ways to convert a map to an array.

  • Using Array.from(map)

    const map = new Map();
    map.set('milk', 200);
    map.set("tea", 300);
    map.set('coffee', 500);
    
    console.log(Array.from(map));
    

    Output,

    image.png

  • Using the spread operator

    We can use the spread operator as well to convert a Map to an array.

    console.log([...map]);
    

Map vs Object: When to use what?

Map has characteristics of both object and array. However, Map is more like an object than array due to the nature of storing data in the key-value format.

The similarity with the object ends here though. The Map is very different from the object in many other ways as we have seen so far. So, which one to use, when? How to take that call?

Use Map when

  • Your need is not simple. You may want to create keys that are non-strings. Storing an object as a key is a very powerful approach. The Map gives it to you by default.
  • You need a data structure where elements can be ordered. Objects do not maintain the order.
  • You are looking for flexibilities without relying on an external library like lodash. You may end up using a library like lodash because we do not find methods like, has(), values(), delete() or a property like, size with the object.

    Map makes it easy for you by providing them by default.

Use Object when

  • You do not have any needs like the above.
  • You rely on JSON.parse() as, a Map cannot be parsed with it.

To end it

Hope it was a useful explanation of the Map data structure in JavaScript. Give it a try if you are not using it already.

I shall be explaining another data structure called, Set in my next article. Please stay tuned.

You may also like other JavaScript related articles,


If it was useful to you, please Like/Share so that, it reaches others as well. To get an email notification on my latest posts, please subscribe to my blog by hitting the Subscribe button at the top of the page.

Follow me on twitter @tapasadhikary for more updates.

Did you find this article valuable?

Support Tapas Adhikary by becoming a sponsor. Any amount is appreciated!