The love affair between Map and Object in JS

The love affair between Map and Object in JS

·

3 min read

It is well known that the two data structures Object and Map in JavaScript are very similar. However, if we look deeper into the underlying principles, there are still a lot of differences between them, and comparing them can help us better understand their uses and scenarios.

Key type

Object

The key of Object must be of type String or Symbol, and the toString method is called by default to convert the key to type String, so there may be [a key overwrite problem](# key uniqueness).

Note: Array and Function are essentially inheritance of Object, so both have corresponding toString methods.

Object keys

The Object.toString method is called when an object is used as a key to convert it to an object string ("[object Object]").

({}.toString()); // "[object Object]"

var obj = {};
obj[{}] = "ok";
console.log(JSON.stringify(obj)); // {"[object Object]": "ok"}

Array Keys

The Array.toString method is called when using an array as a key to convert it to an empty string ("").

[].toString(); // ""

var obj = {};
obj[[]] = "ok";
console.log(JSON.stringify(obj)); // {"": "ok"}

Function Keys

Converting a function to a function string ("() => {}") is done by calling the Function.toString method when the function is used as a key.

(function test() => {}).toString(); // "() => {}"

var obj = {};
obj[() => {}] = "ok";
console.log(JSON.stringify(obj)); // {"() => {}": "ok"}

Map

Map supports arbitrary types of keys.

Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values.

map storage structure

Key uniqueness

Object key override with the same name

Since the toString method is called by default for Object keys, multiple assignments will be overwritten if the current key is an empty object ({}) or an empty array ([]).

var obj = {};
obj[{}] = "step1";
obj[{}] = "step2";
console.log(JSON.stringify(obj)); // {"[object Object]": "step2"}

Map unique keys

Each key in Map is unique, and in the procedure Map compares the type or reference of the stored key. Suppose the current Map has two empty objects ({}) stored in it, both of the same type, but referenced at different memory addresses in the Stack, then the Map will determine that they are two separate keys, as in the following example.

Map unique key

Traversal order

Object unordered

The result of traversing Object is an unordered list.

var obj = { 1: 1, 2: 2, a: "a", f: "f" };
console.log(Object.keys(obj)); // ["1", "2", "a", "f"]

obj = { a: "a", 1: 1, 2: 2, f: "f" };
console.log(Object.keys(obj)); // ["1", "2", "a", "f"]

Map ordered

The result after traversing Map is an ordered list.

var map = new Map();

map.set(1, 1);
map.set("a", "a");
map.set(2, 2);
console.log([... .map.values()]); // [1, "a", 2]

Traversable

Object

Object does not implement an iterator (@@iterator) interface and cannot be traversed using for of, but can be traversed using methods such as for in. Of course, Object does not support it natively but can extend @@iterator to implement iterators, see iterator for details.

var obj = { a: "a", 1: 1, 2: 2, f: "f" };

for (key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key);
  }
}

console.log(Object.keys(obj)); // ["1", "2", "a", "f"]

Map

Map internally implements the traverser (@@iterator) interface, which can be traversed using for of.

Map.prototype [ @@iterator ] ( )

var map = new Map();

map.set(1, 1);
map.set("a", "a");
map.set(2, 2);

for (item of map) {
  console.log(item);
}

Inheritance Relationships

From the prototype chain inheritance structure, we can see that Map actually inherits from Object at the bottom, i.e. Map is an instance object of Object, and conversely Object is not an instance object of Map.

map inheritance relationship

Reference documentation

Official ECMA documentation

Did you find this article valuable?

Support Jweboy's blog by becoming a sponsor. Any amount is appreciated!