DEV Community

Cover image for How Maps solve the limitations of Objects in JavaScript
Jay Cruz
Jay Cruz

Posted on

How Maps solve the limitations of Objects in JavaScript

An overview of Maps in JavaScript and how they can make up for limitations that come with using objects.

In JavaScript, objects are one of the most commonly used data structures. They provide you with a way to organize and store data as key/value pairs. While this is the case they also come with some limitations that are worth pointing out. In this article, we’ll be going over what those limitations are and show how using the Map object vs regular objects can be more effective.

What is the Map object?

The Map object was first introduced with the ES6 version of JavaScript. Like regular objects, they can contain key, value pairs and allow you to add, retrieve, remove, and check for those keys and values.

To create a new instance of the Map object we can do so as the following:

const map = new Map([
    ["key", "value"]
]);
Enter fullscreen mode Exit fullscreen mode

There are several built-in properties and methods that come with an instance of the Map object. These include but are not limited to some of the more common ones such as the following:

  • .set() - Adds key, value pairs with the first argument being the key and second being the value .set(key, value)

  • .get() - Retrieves a value linked to a key by passing in the specified key as the only argument .get(key)

  • .delete() - Removes a key, value pair identified by the passed-in key name .delete(key)

  • .has() - Checks whether or not a key, value pair exists and returns a boolean value. Takes in the key as the only argument .has(key)

  • .size - Returns an integer representing the number of key/value pairs contained within the Map object

For more about the Map object’s built-in properties and methods check out this link.

Using Map to avoid limitations of using objects

To show how using the Map object can solve for limitations that arise when using objects let’s go over what these limitations are and how we can avoid them using maps.

Objects are not guaranteed to be ordered

Although this has changed since JavaScript has updated to ES6 the ordering for the key/value pairs of a regular object can still be unreliable.

Take the following object we declared for example:

const obj = {
    1: 2,
    0: false,
    "Greet": "Hello World",
    a: "b",
    c: "c"
}
Enter fullscreen mode Exit fullscreen mode

When we log obj to the console it displays a different ordering from what we originally declared it with:

{0: false, 1: 2, Greet: 'Hello World', a: 'b', c: 'c'}
Enter fullscreen mode Exit fullscreen mode

When we try declaring the same key/value pairs with a map,

const map = new Map([
    [1, 2],
    [0, false],
    ["Greet", "Hello World"],
    ["a", "b"],
    ["c", "c"]
]);
Enter fullscreen mode Exit fullscreen mode

we instead get the original order in which they were declared.

{1 => 2, 0 => false, 'Greet' => 'Hello World', 'a' => 'b', 'c' => 'c'}
Enter fullscreen mode Exit fullscreen mode

No method to quickly determine the length or size of an object

With an object, we determine the size manually by iterating over the object using a for loop and a counter or using the Object.entries() method along with .length.

const obj = {
    1: "one",
    2: "two",
    3: "three"
};

Object.entries(obj).length; // 3
Enter fullscreen mode Exit fullscreen mode

When we need to find out the number of key/value pairs in a Map object we can use the .size property to easily get it.

const map = new Map([
    [1, "one"],
    [2, "two"],
    [3, "three"]
]);

console.log(map.size); // 3
Enter fullscreen mode Exit fullscreen mode

Map object is naturally iterable, Object is not

To iterate over objects we usually use a for..in loop to manually get each key and value.

// obj = {1: 'one', 2: 'two', 3: 'three'}

for (let key in obj) {
    console.log(key, ": ", obj[key]);
    // 1: one
    // 2: two
    // 3: three
}
Enter fullscreen mode Exit fullscreen mode

Note however that Object.keys() and Object.values() or Object.entries() can also be used to make an object iterable.

Object.entries(obj)
    .forEach(entry => console.log(entry[0], ": ", entry[1]));
    // 1: one
    // 2: two
    // 3: three
Enter fullscreen mode Exit fullscreen mode

A map object can be easily and directly iterated over with methods like .forEach() to access each value.

// map = {1 => 'one', 2 => 'two', 3 => 'three'}

map.forEach(value => console.log(value));
// one
// two
// three
Enter fullscreen mode Exit fullscreen mode

Key types of objects can be only string or symbol

When declaring Javascript objects, the only types we can use as the key is a string or a symbol.

const obj = {
    ["key"]: "value"
};

console.log(obj); // automatically converts array key to a symbol: {key:'value'}

const obj2 = {
    ["key"]: "value",
    function key(), "Value"
};

console.log(obj2); // throws an error
Enter fullscreen mode Exit fullscreen mode

While keys for a regular JavaScript object can only be either a string or a symbol the same does not go for Map objects. For the Map object, its keys can be of any type including functions, objects, and arrays.

const map = new Map([
    [ ["key"], "value" ],
    [ function key() {}, "value" ],
    [ { "a": 1 }, "b" ],
]);

console.log(map); 
// {Array(1) => 'value', ƒ => 'value', {…} => 'b'}
Enter fullscreen mode Exit fullscreen mode

Summary

In Javascript, Maps are very useful data structures. They provide more flexibility than regular objects do, for example, Maps give us the ability to use any data type as a key while also maintaining the original ordering they’re declared with.

Next time you’re reaching for that plain ol’ JavaScript object to store some sort of complex data, consider using a map. Depending on the use case it may just serve you better!

Discussion (1)

Collapse
lukeshiru profile image
Info Comment hidden by post author - thread only accessible via permalink
LUKESHIRU

Not the first post I see on the topic, and I always find puzzling that folks actually need Map at all for this kind of things:

Objects are not guaranteed to be ordered

If the order matters, you should be using an array, not an object.

No method to quickly determine the length or size of an object.

  1. Why do you need to know the amount of properties that an object has when you can loop over them without that?
  2. Same as the previous item, if length is something you care about, you should be using an array, not an object.

Map object is naturally iterable, Object is not

If you want to map over values, you have Object.values, if you want to map over keys, you have Object.keys, if you want to map over both, you have Object.entries:

Object.values(object).forEach(value => console.log(value));
Object.keys(object).forEach(key => console.log(key));
Object.entries(obj).forEach(([key, value]) => console.log(key, value));
Enter fullscreen mode Exit fullscreen mode

Key types of objects can be only string or symbol

Why is that a bad thing? How would you serialize a Map with object or function keys as JSON?


Here’s a few things that usually folks "forget" to mention about Map:

  • Map can't be easily serialized as JSON, nor easily parsed from JSON.
  • To access a value from Map you need to do map.get(key) vs. object.key.
  • To create a new Map you need to do new Map([["foo", 0], ["bar", 1]]) vs. { foo: 0, bar: 1 }.
  • Performance is obviously worse because you now have an instance of an object full of methods to do the things that you could do with external methods/functions and plain objects.
  • Map favors mutation (you can work with "immutable Maps" but then the performance suffers even more). If you're working with immutable data (like with React), Map is not useful at all.
  • You loose easy deconstructing: const { foo } = object.

And I'm sure there's more. Don't get me wrong, Maps have their place, the only thing that makes me write this comment is the fact that is usually presented as a way of solving limitations that aren't there actually, or that are pretty easy to solve without Map, and before trying to use Map everywhere, we should really consider what we are sacrificing and what we are gaining from it.

Cheers!

Some comments have been hidden by the post's author - find out more