Map in JavaScript and when it’s a better choice than Object

The Map object stores data in key-value pairs similar to the regular objects in JavaScript. Unlike JavaScript objects, Map provides some utility methods to manipulate the data and more.

const map = new Map();
map.set('x', 5);
map.set('y', 10);
console.log(map); 
// Map(2) {'x' => 5, 'y' => 10}
console.log(map.get('x')); // 5 

We can pass a 2D key-value pair Array in the Map() constructor to create a Map with initial data.

const map = new Map([['x', 5], ['y', 10]]);
console.log(map); // Map(2) {'x' => 5, 'y' => 10}

Utility methods and property

The Map object provides a couple of helper methods to add/delete data, get data, check if a key exists, and many more. Let’s find them all.

The set() method

This method adds a new data entry with the provided key and value. If the key already exists, then it just updates its value. It returns the updated Map object. The syntax is:

map.set(key, value);

Here the key can be of any data type, including objects, arrays, functions, etc. Similarly, value also can be of any data type.

const fn = function() {};
const ob = { x: 20 };

const map = new Map();
map.set('x', 5);
map.set(10, { a: 10 });
map.set(fn, 'some function');
map.set(ob, 'some object');
map.set(NaN, null);

As the set() returns the updated Map object, we can also chain multiple set() calls together.

const map = new Map();
map.set('x', 10).set('y', 20).set('z', 30);
console.log(map);
// Map(3) {'x' => 10, 'y' => 20, 'z' => 30}

The get() method

This method returns the associated value of the provided key. If the key doesn’t exist, then it returns undefined.

const map = new Map();
map.set('x', 10);
map.set('y', 20);
console.log(map.get('x')); // 10
console.log(map.get('abc')); // undefined

The has() method

This method returns true if the provided key exists in the Map object, otherwise returns false.

const map = new Map();
map.set('name', 'Amitav Mishra');
console.log(map.has('name')); // true
console.log(map.has('address')); // false

The delete() method

This method removes the provided key and its associated value from the Map object. It returns true if the provided key is found and removed, otherwise returns false.

const map = new Map();
map.set('name', 'Amitav Mishra');
console.log(map.delete('name')); // true
console.log(map.get('name')); // undefined
console.log(map.delete('address')); // false

The clear() method

This method removes all the data from the Map object.

const map = new Map();
map.set('x', 5);
map.set('y', 10);
map.set('z', 15);
map.clear();
console.log(map); // Map(0) {size: 0}

The size property

This property returns the number of data stored in the Map object.

const map = new Map();
map.set('x', 5);
map.set('y', 10);
map.set('z', 15);
console.log(map.size); // 3

The key differences between Maps and Objects

There are some differences that make Maps better than regular objects.

The data type of key

In object, we can store keys of only String and Symbol type, whereas, in Map, we can store keys of any data type, including objects, arrays, functions, etc.

const fn = function() {};
const ob = { x: 20 };
const ar = [1, 2];

const map = new Map();
map.set(fn, 'some function');
map.set(ob, 'some object');
map.set(ar, 'some array');
map.set(NaN, 505);

console.log(map.get(fn)); // some function
console.log(map.get(ob)); // some object
console.log(map.get(ar)); // some array
console.log(map.get(NaN)); // 505

Key order

The order of keys in objects cannot always guarantee to be the same as the order they insert in, whereas Map always preserves the correct order of keys. Let’s see some examples to understand better.

Objects generally preserve the order of keys correctly. See the below example.

const ob = {};
ob.x = 10;
ob.y = 20;
ob.z = 30;
console.log(Object.keys(ob)); // ['x', 'y', 'z']

However, when we insert numeric values as keys to an object, the numeric keys appear before in order (in a sorted way) than the other string-valued keys. We can also test this with the for…in loop, and they will appear in the same order.

const ob = {};
ob.x = 10;
ob['30'] = 'thirty';
ob.y = 20;
ob['40'] = 'forty';
ob.z = 30;
ob['20'] = 'twenty';
console.log(Object.keys(ob));
// ['20', '30', '40', 'x', 'y', 'z']

In Map, the order of keys is always the same as the order they insert in.

const map = new Map();
map.set('x', 10);
map.set(30, 'thirty');
map.set('y', 20);
map.set(20, 'twenty');
console.log([...map.keys()]);
// ['x', 30, 'y', 20]

We can also use the for…of loop to test this, and we will get the keys in the same order.

Finding the size of data stored

In object, to find out the total number of key-value pair data stored, first, we need to get all the keys and then count their length, whereas, in Map, we have the size property to find the same.

const ob = { x: 5, y: 10 };
console.log('size: ' + Object.keys(ob).length); // size: 2

const map = new Map([['x', 5], ['y', 10]]);
console.log('size: ' + map.size); // size: 2

Iterating over data

The object is not iterable, whereas Map is iterable. Therefore, we cannot use for…of loop, Array.from(), spread operator, etc., with the object, but we can use them with Map.

To iterate over object data, either we have to use the for…in loop or use Object.keys(), Object.values() etc. and then iterate over their result.

const ob = { x: 5, y: 10 };
for (const key in ob) {
  console.log(key, ob[key]);
}
// or
Object.keys(ob).forEach((key) => console.log(key, ob[key]));

const map = new Map();
map.set("x", 5);
map.set("y", 10);
console.log([...map]); // ["x", 5], ["y", 10]
map.forEach((value, key) => console.log(key, value));
// or
for (const [key, value] of map) {
  console.log(key, value);
}

Performance

The Map has better performance than the object when it comes to additions and deletions of data. Let’s do some performance tests to find out the same.

const ob = {};
console.time('object');
ob.x = 5;
ob.y = 10;
ob.z = 15;
delete ob.y;
ob.a = 20;
delete ob.x;
console.timeEnd('object');

const map = new Map();
console.time('map');
map.set('x', 5);
map.set('y', 10);
map.set('z', 15);
map.delete('y');
map.set('a', 20);
map.delete('x');
console.timeEnd('map');

// output in console
// object: 0.053955078125 ms
// map: 0.01416015625 ms

Here console will print the time taken to execute the tasks. We can see that the object is taking more time than Map to perform the same task.

If you try the above code, you might see different performance times than the above ones, but you will definitely notice that Map executes faster.

Converting object to Map and Map to object

To convert an object into a Map, first, we need to create a 2D key-value pair array and then create a Map from it.

const ob = { x: 5, y: 10 };
const entries = Object.entries(ob); // [['x', 5], ['y', 10]]
const map = new Map(entries);
console.log(map); 
// Map(2) {'x' => 5, 'y' => 10}

Similarly, to convert a Map into an object, first, we can create a 2D key-value pair array and then create an object from it.

const map = new Map();
map.set('x', 5);
map.set('y', 10);
const entries = [...map]; // [['x', 5], ['y', 10]]
const ob = Object.fromEntries(entries);
console.log(ob); // { x: 5, y: 10 }

Now, you must have a good understanding of how Map works and when it performs better than the regular object. So, next time consider all the factors before choosing between Map or Object.

See Next

JavaScript Set object to store unique values

Leave a Reply

Your email address will not be published. Required fields are marked *