The love affair between Map and Object in JS

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:
ArrayandFunctionare essentially inheritance ofObject, so both have correspondingtoStringmethods.
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.

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.

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.




