DEV Community

Lukie Kang
Lukie Kang

Posted on

Javascript Maps

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()
Enter fullscreen mode Exit fullscreen mode

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'],
])
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

Unsuprisingly, changing maps involve a .set method:

   saladMap.set('tomatoes', 10)

   saladMap.get('tomatoes') // 10
Enter fullscreen mode Exit fullscreen mode

Other Handy Map methods:

.has

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

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


Enter fullscreen mode Exit fullscreen mode

## .size

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

 saladMap.size // 2
Enter fullscreen mode Exit fullscreen mode

## .delete

  saladMap.delete('tomatoes') // true
  saladMap.has('tomatoes') // false
Enter fullscreen mode Exit fullscreen mode

## 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'
Enter fullscreen mode Exit fullscreen mode

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

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

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

Enter fullscreen mode Exit fullscreen mode

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]

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)