Dan D Kim

Let's share stories

Javascript - Map vs Object - when to use which?

2020-05-11 Dan D. Kimjavascript

You may have came across the question - when should I use a Map, and when should I use an Object? While the two are both suitable for similar use-cases, there are certain differences between the data structures that will help you make a clear decision.

Here, I will outline a number of those differences.

Key Field

Both an Object and a Map can have key-value pairs.

// Map
{ 'a' => 1, 'b' => 2, 'c' => 3 }

// Object
{ 'a': 1, 'b': 2, 'c': 3 }

But Object has a limited number of data types that can serve as a key. Those are:

  • Integer
  • String
  • Symbol

Whereas for a Map, it can have any of the following as a key:

  • Any primitive data type (Number, String)
  • Object
  • Array
  • Function

In brief, you will need to use a Map if you need to use a more complex data type as a key.

Element Ordering

For an Object, keys are traversed in the following order:

  1. Keys that are Integers
  2. Keys that are Strings
  3. Keys that are Symbols

Within each category, the insertion-ordering is not guranteed.

Below illustrates the ordering for an Object:

b = {
  [Symbol('symbol')]: 1,
  'string': 1,
  2: 1,
}

Object.keys(b).forEach(key => console.log(key))

// 2
// string
// undefined

For a Map, all keys are kept in insertion-order regardless of data type. This is pretty sweet as it becomes useful sometimes. It’s pretty much like Python's OrderedDict

Below illustrates the ordering for a Map:

a = new Map([
  [Symbol('symbol'), 1],
  ['string', 2],
  [2, 3]
])

a.forEach((_, key) => console.log(key))

// Symbol(symbol)
// string
// 2

Inheritance

Map inherits the Object, which means that you can technically still use the Object’s prototype functions on a Map. But with an Object, you cannot use any of Map’s functions since Object is the “parent” class.

Functions

Functional differences between Map and Object may help you decide which one fits your needs.

Creating

In order to create an Object, there are multiple ways to do so:

var object = {}
var object = new Object()
var object = Object.create(null)

But for a Map, there is only one way via the new operand.

var map = new Map()

Since there is only one way, the code for creating a Map will be more consistent across any coding environments.

Getting

In order to retrieve a value from an Object, there are (again) multiple ways:

object.a
object['a']

But for a Map, there is (again) only one way with the function .get():

map.get('a')

Insert

For inserting a key-value pair to an Object, you have the following ways:

object['a'] = 1
object.a = 1

For a Map, we use the .set() method

map.set('a', 1)

Checking If Exists

There are the following ways to check if a key exists in an Object:

var exists = object.a !== undefined
var exists = 'a' in object

On a Map, we use the function .has()

var exists = map.has('a')

Deleting

To delete a property from an Object, the delete keyword is used.

delete object.a

Note that setting the property to undefined does not delete the property.

// this only sets the property to undefined
// but the property still remains as part of the object
object.a = undefined

On a Map, we have the delete():

map.delete('a')

One other thing to note is the return values. delete object.prop will return boolean values based on the following logic

/*
if (non-configurable property && not strict mode) {
  return false
} else if (non-configurable property) {
  throw error
} else {
  return true
}
*/

Whereas with a Map, it will simply return

  • true if the value existed and was deleted
  • false if the value didn’t exist at all

Clearing

To clear all properties on an Object, we need to iterate through all properties and delete them one by one.

On a Map, we can simply use .clear().

map.clear()

Size

To check the number of keys in an Object, you need to use Object.keys() function.

const size = Object.keys(object).length

For Map, we use the .size property.

const size = map.size

Iteration

To iterate through an Object, we can use for... in.

// { 'a': 1, 'b': 2}
for (const key in object) {
  console.log(`${key}: ${object[key]}`)
  // a: 1
  // b: 2
}

Or we can loop through the keys with Object.keys()

Object.keys(object).forEach(key => console.log(`${key}: ${object[key]}`))
// a: 1
// b: 2

For a Map, it’s very different. Map is a built-in iterable, and so it will work with for... of.

// { 'a' => 1, 'b' => 2}
for (const pair of map) {
  console.log(pair)
}

// ["a", 1]
// ["b", 2]

We can also use Map’s built-in forEach() method.

map.forEach((value, key) => console.log(`${key}: ${value}`))

// a: 1
// b: 2

So when do you use what?

Of course, the most important question is what are you trying to do? Do you require a simple Object data type for storing user information, or are you trying to count the number of times a letter/number/object appears in a given input stream?

If we supposedly had a use-case that is suitable for both (meaning, both Object and Map would be a suitable solution), here are my thoughts:

When to use Map:

  • if you need some complex data types as keys, use Map. Pretty useful for coding algorithm questions. Take a look at this Leetcode question for example.
  • if you need the insertion-ordering of your keys, use Map.
  • when in doubt, just use a Map. Map is more flexible in use-cases and has consistent syntax. You just can’t go wrong with it.

When to use Object:

  • if you need to work with JSON at all, use Object. JSON won’t work with Map. Here’s a Stack Overflow post on that. If you need to use complex data type keys and JSON, look up how to serialize a Map.
  • if you know you only need simple data types as keys (String, Integer, Symbol), consider using an Object. Object is probably a little more performant than a Map ({} vs new, direct-access getters and setters vs function calls).

That’s all. Hope you learned something.

Happy programming!