Javascript Maps
Published: 2023-11-14 12:33:26

---
title: Javascript Maps
published: true
description: AKA A data structure I somehow did not know about till the other day...
tags: 
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-11-14 12:28 +0000
---


The annoying thing about development is that there is always something you don't know about. The great thing about development is that there is always something new to learn. Life is all about perspectives. So the other day I came across this in a codebase:

```
const person = new Map()
```

And my reaction was... what is that Map thing, it isn't even an array?! 

So it turns out I have managed to avoid all knowledge of this JS data structure over my years with JS. I don't know how that happened but either I can feel inferior about it or I can do something about it. So I decided to take a little time out to learn about this Map data structure...

## Whats a Map?

So MDN would say:

> The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

Sounds like an object right? You are not wrong but there are some key (no nerdy pun intended) differences:


1. In objects the key field must be an  string or as a symbol. Whereas in map it can be any datatype.
2. Map is an instance of an object but an object is *not* an instance of a map.
3. Maps retain the order of the elements added. Objects...kinda have thier own order too but its complicated.


## Creating a Map

Whereas objects have object literal syntax: `const rabbit = {}` as a handy shortcut. We have to use a constructor for a Map:

```
const empty = new Map()

const filled = new Map([
    [1, 'Apple'],
    [2, 'Banana'],
])
```

## Accessing and Modifying Map properies

For objects we can use dot or []'s to access properties. However for Maps we use a built-in get method:

```
 const saladObj = {
    tomatoes: 5
    potatoes: 3
 }

 saladObj.tomatoes // 5

 const saladMap = new Map([
    ['tomatoes', 5],
    ['potatoes', 3]
 ])

 saladMap.get('tomatoes')
```

Unsuprisingly, changing maps involve a .set method:

```
   saladMap.set('tomatoes', 10)

   saladMap.get('tomatoes') // 10
```


# Other Handy Map methods:

## .has

```
 const saladMap = new Map([
    ['tomatoes', 5],
    ['potatoes', 3]
 ])

 saladMap.has('tomatoes') // true
 saladMap.has('beans') // false


```

 ## .size 

 ```
const saladMap = new Map([
    ['tomatoes', 5],
    ['potatoes', 3]
])

 saladMap.size // 2
 ```

 ## .delete 

 ```
  saladMap.delete('tomatoes') // true
  saladMap.has('tomatoes') // false
 ```

 ## Iterating over a map

 Yup, you can forEach a map...

 ```
 const saladMap = new Map([
    ['tomatoes', 5],
    ['potatoes', 3]
])

saladMap.forEach((value, keys) => {
    console.log(value, keys)
})

// 5 'tomatoes'
// 3 'potatoes'
 ```

 You can also use a good old fashioned for...of:

 ```
   for (const [key, value] of saladMap) {
    console.log(value, key)
   }

// 5 'tomatoes'
// 3 'potatoes'

 ```


## Map.groupBy

This one is quite an interesting way of splitting out data.

```
 const saladMap = new Map([
    ['tomatoes', 5],
    ['potatoes', 3]
])

const lowInventory = {needsMore: true};
const goodInventory = {needsMore: false};
const groupedSalad = Map.groupBy(saladMap, ([key, value]) => value < 4 ? lowInventory : goodInventory)

groupedSalad.get(lowInventory) // [potatoes, 3]
groupedSalad.get(goodInventory) // [tomatoes, 5]

```

## The Object method Gotcha:


Now you could try to add things like you would an object like `saladMap['tomatoes'] = 20` however this would use the underlying Object logic and thus none of the map specific mehods would work on it as intended. And it is super confusing to boot:

```
    const mealMap = new Map()
    mealMap['beans'] = 10 // 10
    console.log(mealMap) // Map(0) {beans: 10, size: 0}
    mealMap['beans'] 10
    mealMap.has['beans'] // undefined
```

Be very careful to avoid using object methods as it creates some weird results as you can see above.


## Why use it instead of an object?

Objects are quick and easy to use, in most small cases they are probably fine but there is some notable occasions I can think of:

- There is a clear order in how Maps are ordered.
- You can use any value for the key which might be handy
- There is more control and simplicity in the way the get/set/has/size works. Objects can be a little wild west and provide odd results in edge cases.
- A little easier to iterate over
- Faster when it comes to actions that involve a rapid additions and removal of key value pairs

However it is not natively supported in JSON so requires a little more effort if thats part of the workflow to be supported. 

## My takeaway on Maps.

Overall, Maps are something I will add to my mental JS toolkit and reach for them in scenarios where they make sense as, in my mind, they are a bit more structured and predictable than regular Objects though I will have to play with them more to truly grok any pitfalls I have not considered. Browser support is also good with only the `.groupBy` being a recent addition.  I want to benchmark that performance benefit as I am curious how quantifiable that would be but I certainly will bear maps in mind for complex algorithms using hashmaps.