DEV Community

Cover image for 5 Reasons To Choose JavaScript Maps Over Objects For Storing Key-Value Pairs(With Examples)
Gus Pear 🍐
Gus Pear 🍐

Posted on

5 Reasons To Choose JavaScript Maps Over Objects For Storing Key-Value Pairs(With Examples)

At 18 I started my "career" as an IT support guy.
At 20 I was flying 80 hours per month as a flight attendant.
At 22 I got my commercial airplane pilot license.
At 29 I was a carpenter and today at 32 I work as a software developer.

If there's one thing I know how to do well, it is how to keep up with changes. Because if you don't, you are left behind. I know firsthand how comfortable it is to use stuff you know by heart instead of giving the 'new' a try.

But discomfort is what makes you grow, as a human and as a dev.

Let's dive head first and see what the "newish" Map can teach us today.

What is the Map object?

Here's the holy source's (MDN) definition:

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.

To put it simply, Map is JavaScript's native hash or dictionary data structure.

Syntax: Map vs Object

Here's a handy cheat sheet that does a great job at showing their syntax differences, posted by Andrej on Twitter.

Image description

He also recorded performance tests if you are interested.

Reason 1: You Won't Overwrite Default Keys By Accident

Map
By default, a Map does not contain any keys. It is a clean slate. It only has what you put into it.

Neither more nor less.

Image description

Object
Objects by default have their prototype, so it contains default keys that could potentially clash with your own keys.

This can be bypassed by passing null as the prototype when creating a new Object: Object.create(null)

Check out the difference:

  • New Object

Image description

  • New Object with null prototype

Image description

Reason 2: It Accepts Any Type As Key

Map
Maps accept any type of key. That includes functions, objects, and all primitives(string, number, boolean, symbol, undefined, null, and bigint).



let obj = { 'a': 'a' };
let func = () => 'hey';

//you can also initialize multiple values at once using array syntax
let map = new Map([[123, true], [true, 123], [obj, 'object'], [func, 'function']])

map.keys() // 123, true, Object, () => 'hey'
map.get(obj) // 'object'
map.get(func) // 'function'
map.get({ 'a': 'a' }) // undefined 
//Object and Functions are stored by reference, so { 'a':'a' } and obj are different objects)


Enter fullscreen mode Exit fullscreen mode

Object
Object's key must be either a String or a Symbol.



let obj1 = { 'a': 'a' };
let func = () => 'hey';

let obj = { 123: true, true: 123, obj1: 'object', func: 'function' };
Object.keys(obj) 
// ['123', 'true', 'obj1', 'func'] converts all keys to strings

obj[func] //undefined
obj['func'] // 'function'


Enter fullscreen mode Exit fullscreen mode

Reason 3: Maps Are Iterable

Map
Maps are natively iterable. That means you can loop over them with for of or .forEach() loops.



const map = new Map();
map.set(0, 'zero').set(1, 'one'); //you can chain .set()

for (const [key, value] of map) {
  console.log(`key: ${key}, value: ${value}`);
}
// key: 0, value: zero
// key: 1, value: one

//if you just want the 'values' or just the 'keys'
for (const key of map.keys()) { // or map.values()
  console.log(key);
}
// 0
// 1

map.forEach((value, key) => console.log(`key: ${key}, value: ${value}`));
// key: 0, value: zero
// key: 1, value: one


Enter fullscreen mode Exit fullscreen mode

Object
Objects are not iterable, even though you can iterate over them using for in and Object.Entries()



let obj = { 0: 'zero', 1: 'one' }

for(let key in obj){
    console.log(`key: ${key}, value: ${obj[key]}`)
}
// key: 0, value: zero
// key: 1, value: one

Object.entries(obj).forEach((item) => console.log(`key: ${item[0]}, value: ${item[1]}`))
// key: 0, value: zero
// key: 1, value: one



Enter fullscreen mode Exit fullscreen mode

Reason 4: Maps Can Be Merged With Arrays, And Converted To Arrays

Map
Maps are Arrays are 100% compatible, making it intuitive move from one to another.

Here's how you can convert a Map into an Array



let map = new Map([ [1, 'one'], [2, 'two'] ]);
Array.from(map) //[ [1, 'one'], [2, 'two'] ] exactly the same array you initially passed in

//or you can use the spread operator
const newArr = [...map];


Enter fullscreen mode Exit fullscreen mode

An Array into a Map



let arr = [ [1, 'one'], [2, 'two'] ];
new Map(arr); //{ 1 => 'one', 2 => 'two' }


Enter fullscreen mode Exit fullscreen mode

Here's how you can merge a Map and an Array



let map = new Map([ [1, 'one'], [2, 'two'] ]);
let arr = [3, 'three']

let combinedMap = new Map(...map, arr); 
// { 1 => 'one', 2 => 'two', 3 => 'three' }

let combinedArr = [...map, arr];
// [ [1, 'one'], [2, 'two'], [3, 'three'] ]


Enter fullscreen mode Exit fullscreen mode

Object
Concerting an Object into an Array



let obj = { 1: 'one', 2: 'two'};
Array.from(obj) // [] doesn't work

//you'd have to do
Array.from(Object.entries(obj))
//[ ['1', 'one'],['2', 'two'] ]

//or
[...Object.entries(obj)]
//[ ['1', 'one'],['2', 'two'] ]


Enter fullscreen mode Exit fullscreen mode

Reason 5: You Can Easily Check The Size

Map
Map has a built-in size property that returns its size.



let map = new Map([1, 'one'], [true, 'true']);
map.size // 2


Enter fullscreen mode Exit fullscreen mode

Object
To check the size of an object you have to combine Object.keys() with .length



let obj = { 1: 'one', true: 'true' };
Object.keys(obj).length // 2


Enter fullscreen mode Exit fullscreen mode

The downside? No Native Method For Serialization And Parsing

Map
Maps have no native support for serialization or parsing to and from JSON.

The documentation suggests implementing your own by using the replacer argument that can be passed to JSON.stringify(obj, replacer) and the reviver argument passed to JSON.parse(string, reviver)

You can find the suggested implementation here

Object
You can natively serialize and parse an Object to and from JSON using JSON.stringify() and JSON.parse() respectfully.

2 Examples of how you can replace Object with Map

#1 Calculating the total price and items of an eCommerce shopping cart

This is one of the examples from the Complete Guide To JavaScript .reduce() Function

Given the following array



const shoppintCart = [
  { price: 10, amount: 1 },
  { price: 15, amount: 3 },
  { price: 20, amount: 2 },
]


Enter fullscreen mode Exit fullscreen mode

We want to return an Object like { totalItems: 6, totalPrice: 45 }

This is the original code



shoppintCart.reduce(
  (accumulator, currentItem) => {
    return {
      totalItems: accumulator.totalItems + currentItem.amount,
      totalPrice:
        accumulator.totalPrice + currentItem.amount * currentItem.price,
    }
  },
  { totalItems: 0, totalPrice: 0 } //initial value object
)
// { totalItems: 6, totalPrice: 45 }


Enter fullscreen mode Exit fullscreen mode

This is a version using Map



shoppintCart.reduce(
  (accumulator, currentItem) => {
      accumulator.set('totalItems', accumulator.get('totalItems') + currentItem.amount);
      accumulator.set('totalPrice', accumulator.get('totalPrice') + currentItem.price);
      return accumulator;
  },
  new Map([['totalItems', 0], ['totalPrice', 0]])
)
// { 'totalItems' => 6, 'totalPrice' => 45 }


Enter fullscreen mode Exit fullscreen mode

#2 A Different Way To Remove Duplicate Objects From An Array

This is a piece of code I actually used in the bookshelf app I made when I started learning JavaScript.

Googling about how to remove duplicate objects from an array led me to the example I share below.

This is an array with one duplicate object



const books = [
  { id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' },
  { id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' },
  { id: 2, title: 'The Alchemist', author: 'Paulo Coelho' },
]


Enter fullscreen mode Exit fullscreen mode

Here's a peculiar way to remove the duplicate:




const uniqueObjsArr = [
   ...new Map(books.map(book => [book.id, book])).values()
];


Enter fullscreen mode Exit fullscreen mode

There is a bit too much happening on the above one-liner.
Let's break it down into chunks so it is easy to digest.



// 1. map the array into an array of arrays with id and book

const arrayOfArrays = books.map(book => [ book.id, book ])
// arrayOfArrays:
/*
[
[ 1, {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' } ],
[ 1, {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' } ],
[ 2, { title: 'Alchemist', author: 'Paulo Coelho' } ]
]
*/

// 2. The duplicate is automatically removed as keys have to be unique

const mapOfUniqueObjects = new Map(arrayOfArrays)
// mapOfUniqueObjects:
/*
{
1 => {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie'},
2 => { title: 'Alchemist', author: 'Paulo Coelho' }
}
*/

// 3. Convert the values back into an array.

const finalResult = [...mapOfUniqueObjects.values()];
// finalResult:
/*
[
{id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie'},
{id: 2, title: 'The Alchemist', author: 'Paulo Coelho'}
]
*/

Enter fullscreen mode Exit fullscreen mode




Conclusion

If you need to store key-value pairs(hash or dictionary) use Map.

If you're only using string-based keys and need maximum read performance, then objects might be a better choice.

Other than that, use whatever you want because, at the end of the day, this is just a blog post of a random dude on the internet Lol.

Here's what we covered:

  • What is the Map object?
  • Syntax: Map vs Object
  • Reason 1: You Won't Overwrite Default Keys By Accident
  • Reason 2: It Accepts Any Type As Key
  • Reason 3: Maps Are Iterable
  • Reason 4: Maps Can Be Merged With Arrays, And Converted To Arrays
  • Reason 5: You Can Easily Check The Size
  • The downside? No Native Method For Serialization And Parsing
  • 2 Examples of how you can replace Object with Map

Thanks for reading!

If you like this article:

*Leave a comment below(You can just say hi!)
*Follow me on Twitter@theguspear

Catch you later,

Gus.

Top comments (34)

Collapse
 
tracygjg profile image
Tracy Gilmore

Hi Gus,
Using a Map over an Object is very often a wise choice but for some reason one I seldom employ; I have no justification other than set in my ways.
One thing to consider is JSON, Objects are supported directly but Maps are not.
Regards, Tracy

Collapse
 
gustavupp profile image
Gus Pear 🍐

Hey Tracy! Good to see you here.

The same goes for me. That is one of the reasons why I wrote the post haha.

There is also the case where most of your colleagues might not be used to it, than you'd prefer to stick with regular objects not to raise eyebrows haha..

Thanks for stopping by again, and have a great week!

Collapse
 
leob profile image
leob

Isn't speed/performance another reason to prefer Map? I've heard that Map is faster with lookups, especially when the number of items is larger.

Collapse
 
gustavupp profile image
Gus Pear 🍐

Hey Leopb! how are you? thanks for leaving a comment!

You're right, Map seems to be faster in most cases, specially for reading.

There is a video in the first section with some tests.

Have a great week my dude!

Collapse
 
peerreynders profile image
peerreynders • Edited

The video doesn't actually cover a map.get(key: string) vs objectMap.key access comparison.

Given the impact that performance of the object.property lookup has on the overall JS runtime performance I would be surprised if map.get(key: string) is faster than object.property for lookup over a [key, value] set not exceeding the size of the number of properties found on a typical object.

Map is optimized for [key, value] deletion and insertion (while maintaining the insertion order for iteration which is something objects per spec don't guarantee even though they often do) and efficiently handling larger [key, value] sets.

Meanwhile an object literal lookup will often perform similar to a switch statement on a string value.

Thread Thread
 
gustavupp profile image
Gus Pear 🍐

Hey Peerreynders! Thanks for you insighful comment!

Apperantly Map outperforms Object in all operations unless you have small integer, array-indexed keys according to this article that run multiple tests.

Have an awesome week!

Thread Thread
 
peerreynders profile image
peerreynders • Edited

The article discusses insertion, deletion, and iteration performance, the scenarios Map is specifically optimized for. Lookup/access performance isn't discussed.

In this test objects are faster on Chrome 109 (V8) while maps are faster on Firefox 109.0 (SpiderMonkey). But once the number of entries increases to 20-30 map performance catches up.

Thread Thread
 
gustavupp profile image
Gus Pear 🍐

I didn't know about the jsbench website! Thanks for sharing the link Peerreynders!

That is an in-depth test.

Thanks once again.

Collapse
 
brense profile image
Rense Bakker

Great post! No native serialization is a big downside though. In modern apps, a lot of data structures go from/to Json APIs, so having data structures with native serialization is extremely convenient. The benefits are there, but only for data that doesn't need to be serialized I think.

Collapse
 
gustavupp profile image
Gus Pear 🍐

Hey Rense! thanks for stopping by.

100% with you, no native serialization/parsing is a big downside. That's one of the reasons I'd choose plain objects.

Have a great week!

Collapse
 
elliot_brenya profile image
Elliot Brenya sarfo

Great post, it's clear that you have a lot of experience and knowledge about the topic. Your examples and explanations make it easy to understand the differences between Map and Object.

Have you tried experimenting with the different use cases of Map and Object in your projects? It would be great to see some examples of how you have utilized these data structures in your own work.

Collapse
 
gustavupp profile image
Gus Pear 🍐

Hey Elliot! how are you? Thanks for taking the time to comment!

I am not that experienced at all lol. I am just curious.

And yes I have used it a few times. The second example at the end of the post is actual code I used in a project I build when buidling my portfolio.

Have a great week man!

Collapse
 
frandev profile image
Franco

Very nice article, thanks a lot! I will use Map and see how that goes.

Collapse
 
gustavupp profile image
Gus Pear 🍐

I am happy that you liked it Franco! Come back and let me know how it went

Collapse
 
raibtoffoletto profile image
RaΓ­ B. Toffoletto

Great research and article πŸŽ‰

Collapse
 
gustavupp profile image
Gus Pear 🍐

Thanks a lot Rai! Happy to hear it

Collapse
 
easyjobber profile image
Easyjobber : le site de jobbing en France • Edited

Great post with good examples and explanations

Collapse
 
gustavupp profile image
Gus Pear 🍐

I am super glad you found it useful Easyjobber!

Passe une bonne semaine!

Collapse
 
awaisalwaisy profile image
Alwaisy al-waisy

map is more like an array and modern data type.

Collapse
 
gustavupp profile image
Gus Pear 🍐

Thanks for commenting Al-waisy!

Collapse
 
kumarkalyan profile image
Kumar Kalyan

Helpful article @gustavupp

Collapse
 
gustavupp profile image
Gus Pear 🍐

I am very glad it was helpful Kumar!

Collapse
 
officialbidisha profile image
Bidisha Das

One of the best articles so far. Was waiting for this.

Collapse
 
gustavupp profile image
Gus Pear 🍐

Wow, you just made my day Bidisha!

I am glad it was helpful!

See you around.