# 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,

```js
const map = new Map();
```
It returns an empty Map.

```shell
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,

```js
const greenrootsBlog = new Map([
        ['name', 'greenroots'],
        ['type', 'blog'],
        ['writer', 'Tapas Adhikary'],
    ]);
```
It returns a Map with three elements,

```shell
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.

```js
// 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,

```shell
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.

```js
// Add a different writer
map.set('writer', 'Someone else!');
```
Now the map output will be,

```shell
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`. 

```js
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.

```js
// 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,

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

```js
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,

```js
// 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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
// 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,

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

### Get all the keys
```js
console.log(ageMap.keys());
```
Output,

```shell
MapIterator {"Jack", "Alan", "Bill", "Sam"}
```
### Get all the values
```js
console.log(ageMap.values());
```
Output,

```shell
MapIterator {20, 34, 10, 9}
```
### Get all the entries(key-value pairs)
```js
console.log(ageMap.entries());
```
Output,

```shell
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
```js
 // 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,

```shell
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.

```js
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.

```js
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`.

```js
Object.fromEntries(map)
```

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

- Using `Array.from(map)`
 
 ```js
  const map = new Map();
  map.set('milk', 200);
  map.set("tea", 300);
  map.set('coffee', 500);

  console.log(Array.from(map)); 
 ```
 Output,

 ![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600601559042/06rtmdgUN.png?border=1,CCCCCC&auto=compress)

- Using the spread operator

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

  ```js
  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.

- [Further read on the Map data structure from MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)

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

You may also like other JavaScript related articles,
- [Build your JavaScript Muscles with map, reduce, filter and other array iterators](https://blog.greenroots.info/build-your-javascript-muscles-with-map-reduce-filter-and-other-array-iterators-cjyo22miw000xzss1ydfqveib)
- [Explain Me Like I am Five: What are ES6 Symbols?](https://blog.greenroots.info/explain-me-like-i-am-five-what-are-es6-symbols-ckeuz5sb8001qafs14of305dw)
- [JavaScript: Equality comparison with ==, === and Object.is](https://blog.greenroots.info/javascript-equality-comparison-with-and-objectis-ckdpt2ryk01vel9s186ft8cwl)
- [My Favorite JavaScript Tips and Tricks](https://blog.greenroots.info/my-favorite-javascript-tips-and-tricks-ckd60i4cq011em8s16uobcelc)

<hr />
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](https://twitter.com/tapasadhikary) for more updates.
