Javascript - Map vs Object - when to use which?
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:
- Keys that are Integers
- Keys that are Strings
- 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 withMap
. 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 anObject
.Object
is probably a little more performant than aMap
({}
vsnew
, direct-access getters and setters vs function calls).
That’s all. Hope you learned something.
Happy programming!