年末了「談個對象」吧

年末了,都回家過年了,是時候好好談談對象了。今天要談的對象是Map和WeakMap。先對這兩個對象進行一個簡單的介紹總結:數組

  • Map 的 key 能夠是任何類型的值,Object 的鍵值只能是 string 和 symbols。
  • Map 實例按照插入的順序存儲數據
  • Map 實例的屬性更容易刪除
  • WeakMap 相比 Map 提供了更優的垃圾回收機制

下面進入正題。數據結構

Map 是什麼

看下 MDN 解釋:函數

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.ui

關鍵詞:鍵值對、按插入順序有序排列、鍵或者值能夠爲任何類型的數據。spa

語法code

new Map([iterable])cdn

咱們再看一下 Map 實例上的屬性和方法。對象

初始化一個 Map 實例:blog

const map = new Map(); // 空的 Map
map.set(1, "first");
map.get(1); // 'first'

const newMap = new Map([
  [1, "zhangsan"],
  [2, "lisi"]
]);
newMap.get(1); // "zhangsan"
newMap.get(2); // "lisi"
複製代碼

鍵值

對象裏的鍵值只能爲字符串。而 Map 實例如上解釋能夠爲任何類型的數據。three

const obj = {};

obj[1] = "one";
obj["1"]; // one
obj[1]; // one

const map = new Map();

map.set(1, "one");
map.set("1", "another one");
// map 包含2組鍵值對: 1, 'one' 以及 '1', 'another one'
複製代碼

這裏再說一下,Map 實例當在比較鍵名的時候採用 sameValueZero 的規則,有點像嚴格等於 ===,但又有兩個例外:NaN 和 NaN、+0 和-0,Map 認爲它們同樣。

另外,Map 實例還支持鏈式調用設置鍵值對,對象只能一次設置一個鍵值對:

const map = new Map();

map
  .set(1, "one")
  .set(2, "two")
  .set(3, "three");
複製代碼

刪除屬性

刪除對象上的屬性值時會一直返回 true,除非這個屬性是

刪除一個 Map 上的屬性時,若是這個屬性存在會返回 true,若是不存在則返回 false。

// 刪除對象屬性
const obj = {
  name: "zhangsan"
};

delete obj.name; // true
delete obj.age; // true,不存在這個屬性一樣會返回 true

// 刪除Map屬性
const map = new Map();

map.set("name", "zhangsan");
map.delete("name"); // true
map.delete("age"); // false
複製代碼

若是刪除對象上全部的屬性呢?或許能夠這樣:

const obj = { 1: 234 };

obj = {};
複製代碼

可是這樣的話,你其實只是把一個新的空對象複製給這個實例,而原先的舊對象並不必定就被刪除了(要看垃圾回收機制),若是別的地方對它還有引用,那它就還會一直存在。

for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    delete obj[key];
  }
}
複製代碼

Map 實例就能很好地處理這個問題:map.clear();

遍歷

如開頭 MDN 上的解釋同樣, Map 的遍歷更好預測。

const obj = {};

obj[5] = "five";
obj[4] = "four";
Object.entries(obj); // [ ['4', 'four'], ['5', "five"] ]

const map = new Map();

map
  .set(5, "five")
  .set(4, "four")
  .entries(); // [ 5 => "five", 4 => "four" ]
複製代碼

和對象相似,Map 也有 3 種方法用於遍歷對象:

  • map.keys() 返回鍵名組成的數組
  • map.values() 返回鍵值組成的數組
  • map.entries() 返回包含一組組鍵值對的可遍歷的數組

相互轉換

Map 構造函數接收一個數組或者可迭代(iterable)對象,因此對象轉 Map 實例的時候咱們能夠用 Object.entries 方法處理:

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

const map = new Map(Object.entries(obj));

console.log(map.get("one")); // 1
複製代碼

那麼又如何把 Map 實例轉成對象呢?還好咱們有 Object.fromEntries 方法,用法和 Object.entries 相反:

const map = new Map();

map.set("one", 1);
map.set("two", 2);

const obj = Object.fromEntries(map);

console.log(obj.one); // 1
複製代碼

Map vs WeakMap

WeakMapMap 相似,主要的不一樣點有兩處:

  1. WeakMap 的只接受對象做爲鍵名。
const map = new WeakMap();
map.set(1, 2);
// TypeError: Invalid value used as weak map key

map.set({}, 1);
複製代碼
  1. WeakMap 鍵名所指向的對象,不計入垃圾回收機制。
let obj = { name: "Matt" }; // object can be accessed

let map = new Map();
map.set(obj, true);

obj = null; // 儘管對象被重寫了,可是舊對象依然能夠在map裏訪問到
複製代碼

WeakMap 是怎麼處理這種狀況的:

let obj = { name: "Matt" };

let weakMap = new WeakMap();
weakMap.set(obj, true);

obj = null; // 重寫對象,同時也會在 weakMap 裏被刪除
// weakMap 如今是空
複製代碼

WeakMap 只有四種方法:get, set, delete, has。 之因此沒有 size等屬性或者方法,就是由於這個機制, WeakMap 實例的長度可能會隨時變化,因此從規則上就禁止去訪問 WeakMapsize 屬性,天然也不會提供用於遍歷的那幾個屬性了。

總結

從一些共同點以及不一樣點介紹了對象以及 Map 的特性,但願能幫助到你瞭解他們的優缺點,進而在適合的場景選用適合的數據結構。

關注咱們

相關文章
相關標籤/搜索