博客 / 詳情

返回

Map 與 Object 之相愛相殺

ss

眾所周知 JavaScriptObjectMap 這兩種數據結構很相似,
但深究底層原理來看,這兩者本質上還是存在了不少差異,通過區別比較能幫助我們更好地理解它們的用處和使用場景。

鍵類型

Object

Object 的鍵必須是 StringSymbol 類型,並默認調用 toString 方法將鍵轉化為 String 類型,因此可能會存在同名鍵覆蓋問題。

注:ArrayFunction 本質是對 Object 的繼承,因此都有對應的 toString 方法。

對象鍵

將對象作為鍵時會調用 Object.toString 方法將其轉化為對象字符串 ("[object Object]")。

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

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

數組鍵

將數組作為鍵時會調用 Array.toString 方法將其轉化為空字符串 ("")。

[].toString(); // ""

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

函數鍵

將函數作為鍵時會調用 Function.toString 方法將其轉化為函數字符串 ("() => {}")。

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

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

Map

Map 支持任意類型的鍵。

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

map存儲結構

鍵唯一性

Object 同名鍵覆蓋

由於 Object 的鍵默認會調用 toString 方法,因此當前鍵如果是空對象({})或者空數組([])的話,多次賦值會出現被覆蓋的情況。

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

Map 唯一鍵

Map 中每個鍵都是唯一的,在存儲過程中 Map 會對存入鍵的 類型引用 進行比較。假設當前 Map 存入了兩個空對象({}),兩者類型相同,但在 中引用的內存地址不同,那麼 Map 就會認定為是兩個獨立鍵,示例如下:

Map唯一鍵

遍歷次序

Object 無序

在遍歷 Object 後得到的結果是一個無序列表。

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 有序

在遍歷 Map 後得到的結果是一個有序列表。

var map = new Map();

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

可遍歷

Object

Object 沒有實現遍歷器(@@iterator)接口,無法使用 for of 遍歷,但可以用 for in 等方法遍歷。當然,Object 原生不支持但可以擴展 @@iterator 實現遍歷,詳見 iterator。

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 內部實現了遍歷器(@@iterator)接口,可以使用 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);
}

繼承關係

從原型鏈繼承結構中,我們可以看到 Map 底層實際上是繼承自 Object ,即 MapObject 的實例對象,反之 Object 並不是 Map 的實例對象。

map繼承關係

參考文檔

ECMA 官方文檔

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.