ES6學習之Map WeakMap

帶鍵(key)的集合

Map、WeakMap(映射) 和 Set(集合) 對象承載的數據元素可以按照插入時的順序被迭代遍歷。

Map

與Object的比較
Map的key值可以是任意類型(可以將原始值(字面量)存儲爲鍵),Object只能是字符串或Symbol。
Map可通過size獲取數量(length=0),Object只能手動計算。
Map遍歷遵循數據的插入順序,Object自動排序。
Map可作爲迭代器被迭代,Object需要其他方式(for in )迭代

使用

let map = new Map(); // 創建空的map
map.set(1, 'map中key爲1的value'); // 添加或修改
console.log(map.get(1)); // 獲取,返回value或undefined
console.log(map.has(1)); // 判斷是否包含,返回Boolean
map.delete(1); // 刪除

let obj = {
	name: '喬峯'
};
let map2 = new Map([[1, 'map2中key爲1的value'], [2, obj]]); // 創建並初始化map,初始化格式[[key, value],[key, value]...]
console.log(map2.size); // 獲取數量

let map3 = new Map(map2); // 淺拷貝
console.log(map3 == map2); // false
let map3_2 = map3.get(2);
map3_2.name = '虛竹';
console.log(obj); // {name:"虛竹"}
map3.clear(); // 清空

鍵的相等

// get的依據類似'===',雖然NaN!==NaN,但Map.get(NaN)可以被獲取到
// 注意:+0 === -0
// Map可以設置鍵爲NaN null undefined並獲取
let map = new Map();
let obj = {};
map.set(NaN,1);
map.set({},2);
map.set(obj,3);
console.log(map.get(NaN)); // 1
console.log(NaN===NaN); // false
console.log(map.get({})); // undefined
console.log({}==={}); // false
console.log(map.get(obj)); // 3
console.log(obj===obj); // true

遍歷

let map = new Map([
    [1, 'key爲1的value'],
    [2, 'key爲2的value'],
    [3, 'key爲3的value']
]);
let entries = map.entries(); // 返回按插入順序包含key/value映射的Iterator迭代器對象
let keys = map.keys(); // 返回按插入順序包含key的Iterator迭代器對象
let values = map.values(); // 返回按插入順序包含value的Iterator迭代器對象

// for of遍歷
for (let [key,value] of map) {}
for (let [key,value] of entries) {}
for (let key of keys) {}
for (let value of values) {}

// forEach遍歷(Iterator不能用forEach遍歷)
map.forEach((value,key) => {});

與數組交互
創建和轉化

let arr = [
    [1, 'key爲1的value'],
    [2, 'key爲2的value'],
    [3, 'key爲3的value']
];
let map = new Map(arr); // Array轉Map

let arr2 = Array.from(map); // Map轉Array
let arr3 = [...map]; // 效果同arr2
console.log([...map]); // 展開運算符本質上是將Map對象轉換成數組,打印同arr

// 補充說明:
// Array.from從一個類似數組或可迭代對象,創建一個新的淺拷貝的數組
let arrLike = {
    0: 'key爲0的value',
    1: 'key爲1的value',
    2: 'key爲2的value',
    length: 3
}; // 類似數組對象
console.log(Array.from(arrLike)); // ['key爲0的value', 'key爲1的value', 'key爲2的value']

合併:Map與Map或數組對象可以合併,但是會保持鍵的唯一性,同鍵被覆蓋。

let first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// 合併兩個Map對象時,如果有重複的鍵值,則後面的會覆蓋前面的。
let merged = new Map([...first, ...second]);

// 合併Map和數組時,如果有重複的鍵值,則後面的會覆蓋前面的。
let merged2 = new Map([...first, [3, 'ent']]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
console.log(merged2.get(3)); // ent

規範
使用對象屬性賦值方法可以給Map添加屬性,但不會被Map的方法識別

let map = new Map();
map['age'] = 18;
console.log(map.get('age')); // undefined
map.delete('age'); // 並沒有刪除什麼
console.log(map.age); // 18

WeakMap

與Map的區別
1.key必須是對象類型(Object),不能是基礎數據類型
2.key鍵所引用(指向)的對象是弱引用。注意不是value值指向的對象。
3.Map是可迭代的(iterable),WeakMap是不可迭代的(key是弱引用)。

Map原理(個人理解)
Map會創建兩個數組,一個存放鍵[…keys],一個存放值[…values],使用其API共用兩個數組。
當從Map中取(get)某個值或修改(set)某個值時,Map會遍歷所有的鍵[…keys],找到後利用索引再去獲取值[…values]。這樣有兩個缺點:
1.賦值和搜索都需要遍歷,消耗時間和內存。
2.[…keys]和[…values]會一直保留對key value的引用,這種引用使得垃圾回收算法不能回收處理他們,即使沒有其他任何引用存在了。也就是會造成內存泄漏。

弱引用

解釋1:在計算機程序設計中,弱引用與強引用相對,是指不能確保其引用的對象不會被垃圾回收器回收的引用。一個對象若只被弱引用所引用,則被認爲是不可訪問(或弱可訪問)的,並因此可能在任何時刻被回收。

解釋2:垃圾回收機制不考慮對該對象的引用。如果對象沒有在其他地方被引用,則垃圾回收機制會回收該對象所佔用的內存。

解釋3:WeakMap可以把一個對象所關聯的數據和該對象的生命週期聯繫起來。當對象被銷燬,其關聯的數據也被釋放。

// 個人理解舉例
let obj = {
    name:'喬峯'
};
let obj2 = {
    name:'虛竹'
};
let map = new Map();
map.set(obj, 1);
let weakMap = new WeakMap();
weakMap.set(obj2, 1);

obj = null; // 手動刪除全局對{name:'喬峯'}的引用
obj2 = null; // 手動刪除全局對{name:'虛竹'}的引用

setTimeout(()=>{
    console.log(map); // Map(1) {{…} => 1}
    console.log(weakMap); // WeakMap {}
}, 10000); // 設置時間長點,等待垃圾回收

使用

// 弱引用不能被枚舉。所以WeakMap不能被遍歷
let obj = {};
let weakMap = new WeakMap(); // 創建
weakMap.set(obj,1); // 添加/修改
console.log(weakMap.get(obj)); // 獲取
console.log(weakMap.has(obj)); // 判斷是否包含
weakMap.delete(obj); // 刪除

// WeakMap的key是弱引用,所以WeakMap是不可被迭代的
// 下面代碼報錯:weakMap is not iterable
for(let [key, value] of weakMap) {}

// weakMap.clear()已被廢棄,可重新創建一個空WeakMap替換來實現清空
weakMap = new WeakMap();

應用場景
1.給Dom添加數據或註冊監聽事件

let myImg = document.getElementById('myImg');
let weakMap = new WeakMap();
weakMap.set(myImg, {name:'',description:'',size:''});
// 或者
weakMap.set(myImg, function() {
	...handler
});
myImg.addEventListener('click', weakMap.get(myImg));

// 當myImg元素在頁面中被註銷(刪除)後,weakMap綁定的數據或回調方法也會被垃圾回收機制處理

2.數據緩存
3.私有屬性

參考

MDN:
Keyed collections
Map MDN
WeakMap MDN
其他:
ES6 系列之 WeakMap
WeakMap的應用場景

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章