ES6 — Object vs. Map for storing key value pairs
By: Olivier Picault
Tags: JavaScript, Programming, Web Development, Coding, ES6

We very often need to store key value pairs for various reasons. I found that most of the time people (including myself) use the Object data structure to achieve this though ES6 provides a Map data structure which really looks like what we should be using.

Let’s try to see what are the differences between these two shall we ?

Disclosure: I’ll call key both Map key (which is correct) and Object property as we’re talking about storing key value pairs in this post.

Basics

There are no big differences when using one or another when it comes to basic operations like adding or getting a value.

Object

// init

const keyValue = {} // add

keyValue['firstname'] = 'tony' // get

keyValue['firstname']

Map

// init

const keyValue = new Map() // add

keyValue.set('firstname', 'tony') // get

keyValue.get('firstname')

Interesting thing to notice: both return undefined when trying to get a value from a key that doesn’t exist

const o = {}

o['firstname'] // undefined const m = new Map()

m.get('firstanme') // undefined

Iterate

Storing and getting values is fine but we also most than often need to iterate through the collection.

It’s pretty easy with Map as it’s an iterable. This means you can directly use the built-in forEach function:

const kv = new Map()

kv.set('firstname', 'tony')

kv.set('lastname', 'stark') kv.forEach((value, key) => console.log(key, value)) // firstname tony

// lastname stark

which is not possible with Object . There are though many ways to overcome this issue. Two of them would be:

const kv = {}

kv['firstname'] = 'tony'

kv['lastname'] = 'stark' Object.keys(kv).forEach((key) => console.log(key, kv[key])) // firstname tony

// lastname stark

and

Object.entries(kv).forEach((entry) => console.log(entry[0], entry[1])) // firstname tony

// lastname stark

It’s definitely easier, less verbose and more readable with Map

Check for a key

Checking for a key in Map is pretty easy:

const kv = new Map()

kv.set('firstname', 'tony')

kv.set('lastname', 'stark') kv.has('firstname') // true

kv.has('nickname') // false

Where it’s not that so simple with an Object :

const kv = {}

kv['firstname'] = 'tony'

kv['lastname'] = 'stark' Object.prototype.hasOwnProperty.call(kv, 'firstname') // true

Object.prototype.hasOwnProperty.call(kv, 'nickname') // false

More details about checking if an object has a property here.

Here again Map seems handier

Count / Length / Size

Guess what it’s easier with Map as it has a built-in property

const kv = new Map()

kv.set('firstname', 'tony')

kv.set('lastname', 'stark') kv.size // 2

where with Object you have to create an iterable and then get its length

const kv = {}

kv['firstname'] = 'tony'

kv['lastname'] = 'stark' Object.keys(kv).length // 2

Time complexity

Which one perform better ? I wrote a small piece of code based on this StackOverflow post and ran it with size = 1000 :

const benchmarkMap = size => {

console.time('Map insert')

const kv = new Map()

for (let i = 0; i < size; i++) {

kv.set(i, i)

}

console.timeEnd('Map insert')

console.time('Map retrieve')

for (let i = 0; i < size; i++) {

kv.get(i)

}

console.timeEnd('Map retrieve')

} const benchmarkObject = size => {

console.time('Object insert')

const kv = {}

for (let i = 0; i < size; i++) {

kv[i] = i;

}

console.timeEnd('Object insert')

console.time('Object retrieve')

for (let i = 0; i < size; i++) {

kv[i]

}

console.timeEnd('Object retrieve')

}

and here is what I got:

Map insert: 0.099853515625ms

Map retrieve: 0.0751953125ms

Map insert: 0.095947265625ms

Map retrieve: 0.093994140625ms

Map insert: 0.076904296875ms

Map retrieve: 0.06005859375ms

Map insert: 0.0869140625ms

Map retrieve: 0.05908203125ms

Map insert: 0.078125ms

Map retrieve: 0.057861328125ms Object insert: 0.041015625ms

Object retrieve: 0.028076171875ms

Object insert: 0.035888671875ms

Object retrieve: 0.02783203125ms

Object insert: 0.038818359375ms

Object retrieve: 0.029052734375ms

Object insert: 0.035888671875ms

Object retrieve: 0.031005859375ms

Object insert: 0.035888671875ms

Object retrieve: 0.029052734375ms

Using Object looks to be faster but note that we’re talking about milliseconds here and dealing with 1000 key value pairs.

Interesting things to know

Object can only store string as key where it could be anything for Map . As an example the following is totally ok

const m = new Map()

m.set(['a', 'b'], true)

m.set(['a', 'c'], false)

Even if you specify a number as key, it will be treated as a string

const o = {}

o[1] = 'iron man'

o[1] // 'iron man'

o['1'] // 'iron man'

Object has a prototype this means there are already some keys set

const o = {}

o['constructor'] // ƒ Object() { [native code] } const m = new Map()

m.get('constructor') // undefined

where Map doesn’t

JSON supports Object but not Map

const kv = {}

kv['firstname'] = 'tony'

kv['lastname'] = 'stark' JSON.stringify(kv) // '{"firstname":"tony","lastname":"stark"}'

where

const kv = new Map()

kv.set('firstname', 'tony')

kv.set('lastname', 'stark') JSON.stringify(kv) // '{}'

so if you need to serialize the data to send it through a HTTP call for example Map wouldn’t be a good choice

Which one to chose ?

In my opinion Map should be your way to go when it comes to storing key value pairs unless you need to serialize the data. You can use not only string as keys, the fact that it is an iterable on top of has() and size will ease your life.

Object should be use when you want to represent something. You would thus probably use different logic for each property.