JavaScript Map與WeakMap

admin發表於2019-04-25

本文將詳細介紹一下Map與WeakMap物件的具體用法。

上述兩種資料結構是ES2015新增,與已有的物件直接量非常相近。

一.Map物件:

對於物件直接量非常相似,都是鍵值對集合,但是Map物件更為完全,且API豐富。

兩者的核心區別是,物件直接的鍵只能是字串型別或者Symbol型別資料,但是Map鍵可以是各種型別。

可能有些朋友感覺物件直接量的鍵也可以是非字串或者Symbol型別,看如下程式碼例項:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let dataObj = {};
let keyObj = {};
dataObj[keyObj] = "螞蟻部落";
console.log(dataObj[keyObj]);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012008qg0xznxm3sk9z4n6.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼簡單分析如下:

(1).建立兩個物件直接量。

(2).將一個物件直接量作為另一個的鍵,然後賦值。

(3).並且可以通過作為鍵的物件訪問對應資料。

(4).上述程式碼上述程式碼並無不妥,貌似上文中的結論出錯了,事實並非如此。

再來看一段程式碼例項:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let dataObj = {};
let keyObj = {};
dataObj[keyObj] = "螞蟻部落";
console.log(dataObj[keyObj]);
console.log(dataObj["[object Object]"]);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012040t2yja4qjeew74eec.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).雖然在外觀上看,確實是物件作為直接量的鍵。

(2).但是其內部已經將其轉換為字串"[object Object]"。

前面程式碼都是關於非Map物件的內容,現在該輪到本文的主角Map出場了。

下面演示一段關於Map物件的程式碼,首先對齊有一個比較直觀的感受:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map();
let objKey = {p: "antzone"};
map.set(objKey, "螞蟻部落")
console.log(map.get(objKey));
console.log(map.has(objKey));

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012110ep01lezzwoe4v5e2.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼簡單分析如下:

(1).通過建構函式Map建立一個Map物件例項。

(2).然後建立一個物件直接來你個objKey作為map物件的鍵。

(3).通過set方法可以為map物件新增一個成員。

(3).get方法可以獲取對應鍵的值,has方法可以判斷對應的成員是否存在。

可以看到Map物件比物件直接量根據有可操作性,API眾多,上面演示了少數幾個。

Map建構函式的引數可以是陣列,直接看程式碼例項:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map([["webName", "螞蟻部落"], ["url", "www.softwhy.com"]]);
console.log(map.size);
console.log(map.has("webName"));
console.log(map.get("webName"));
console.log(map.has("url"));
console.log(map.get("url"));

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012139hoju4qmmc5og9mtu.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).Map建構函式的引數是一個陣列,引數陣列是有特點的。

(2).陣列成員也是陣列,每一個成員陣列具有兩個成員,分別作為map物件的鍵和對應的值。

(3).後面程式碼演示了幾個map物件的屬性和相關方法的功能,非常簡單不多介紹。

Map物件的鍵需要注意的幾個細節:

前文介紹過,Map物件的鍵可以是物件,但是不能認為只要長相一樣,就是相同的鍵。

物件是引用型別,比較的實質是物件的引用,也就是物件所儲存的地址。

程式碼演示如下:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map();
map.set({}, "螞蟻部落");
console.log(map.get({}));

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012221f2q8gb00zbtj8rnb.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

可以看到兩個物件雖然長相一模一樣,但是是兩個獨立的物件。

它們的儲存地址不同,所以不能夠列印出字串"螞蟻部落"。

如果鍵是值型別,那麼只要兩者是嚴格相等(===),就可以將它們看做一個鍵。

對於比較特殊的資料NaN,雖然自身與自身都不嚴格相等,但是仍將看做是一個鍵。

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map();
map.set(NaN, 5);
console.log(map.get(NaN));
map.set(-0, 5);
console.log(map.get(+0));

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012246jkt2sfkztff2s2sh.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

上面的執行結果說明了一切,就不再多介紹。

Map物件具有遍歷器介面:

關於遍歷器介面可以參閱JavaScript Iterator遍歷器一章節所以。

毫無疑問Map物件可以使用for of語句和展開運算子,下面通過程式碼簡單演示一下。

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map([["webName", "螞蟻部落"], ["url", "www.softwhy.com"]]);
var arr = [...map];
console.log(arr);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012319rqic9yzeeqhl77ec.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

上面演示了展開運算子的對於map物件的操作,非常簡單不多介紹。

關於展開運算子可以參閱JavaScript 展開運算子一章節。

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let map = new Map([["webName", "螞蟻部落"], ["url", "www.softwhy.com"]]);
for(let elem of map) {
  console.log(elem);
}

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012352p6h88zh6qe88884l.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

上面程式碼演示了for of語句對於Map物件的遍歷操作。

關於for of可以參閱JavaScript for of 語句一章節。

Map物件方法與屬性:

考慮到文章的篇幅問題,Map物件的方法和屬性就不再本文進行介紹。

下面羅列了Map物件的方法和屬性的相關文章連結,需要的朋友可以點選閱讀:

(1).Map.prototype.clear() 方法一章節。

(2).Map.prototype.delete() 方法一章節。

(3).Map.prototype.entries() 方法一章節。   

(4).Map.prototype.forEach() 方法一章節。

(5).Map.prototype.get() 方法一章節。

(6).Map.prototype.has() 方法一章節。

(7).Map.prototype.keys() 方法一章節。

(8).Map.prototype.set() 方法一章節。

(9).Map.prototype.values() 方法一章節。

(10).Map.prototype.constructor 屬性一章節。

(11).Map.prototype.size 屬性一章節。

二.WeakMap 物件:

從名稱來看,此物件與Map物件非常相似,它們的不同點在於WeakMap物件的鍵只能是物件。

還有一點需要注意的是,此物件不可以被遍歷,與Map物件相比,不具有size屬性。

並且鍵名所指向的物件,不會計入垃圾回收機制,看如下程式碼例項:

[JavaScript] 純文字檢視 複製程式碼
let weakmap = new WeakMap()
weakmap.set("num",2)

控制檯截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201904/25/012538azjjdttvntvjedj6.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

物件的鍵是一個值型別資料,所以報錯了,再強調一下,鍵只能是物件。

物件的鍵是物件的弱引用,所對應的物件可能會被自動回收,當物件被回收後,物件自動移除對應的鍵值對。

程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
let wm = new WeakMap();
let element = document.querySelector(".element");
  
wm.set(element, "Original");
wm.get(element) // "Original"
  
element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined

上述程式碼中,物件的鍵是dom元素節點物件,由於WeakMap物件的鍵是物件的弱引用。

也就是說鍵名所指向的物件並不會被計入垃圾回收機制,所以此物件可能會被自動回收。

當我們刪除對應的dom元素節點之後,element所指向的鍵物件自動消失,所以鍵值對也就被刪除了。

WeakMap物件方法與屬性:

(1).WeakMap.prototype.delete() 方法一章節。

(2).WeakMap.prototype.get() 方法一章節。  

(3).WeakMap.prototype.has() 方法一章節。

(4).WeakMap.prototype.set() 方法一章節。

(5).WeakMap.prototype.constructor屬性一章節。

相關文章