【ES6基礎】Map與WeakMap

前端達人發表於2019-05-05
【ES6基礎】Map與WeakMap

ES6裡除了增加了Set(集合型別)外(筆者在這篇文章《Set與WeakSet》有過介紹),今天這篇文章將介紹引入的新型別——Map(對映型別)及WeakMap。對映型別在電腦科學中定義屬於關聯陣列,而關聯陣列的定義是若干鍵值對(Key/Value Pair)組成的集合,其中每個Key值都只能出現一次。

本篇文章將從以下方面進行介紹:

  • Map程式碼示例
  • Map常用方法示例
  • Map與Object的區別
  • weakMap介紹

本篇文章閱讀時間預計5分鐘

Map程式碼示例

Map的鍵和值可以是任何資料型別,鍵值對按照插入順序排列,如果插入重複的鍵值,後面的鍵值會覆蓋前者,下段程式碼是個簡單示例,演示了Map的一些用法:

let map = new Map();
let o = {n: 1};
map.set(o, "A"); //add
map.set("2", 9);
console.log(map.has("2")); //check if key exists
console.log(map.get(o)); //retrieve value associated with key
console.log(...map);
console.log(map);
map.delete("2"); //delete key and associated value
map.clear(); //delete everything
//create a map from iterable object
let map_1 = new Map([[1, 2], [4, 5]]);
console.log(map_1.size); //number of keys複製程式碼

上述程式碼將會輸出

true
A
[ { n: 1 }, 'A' ] [ '2', 9 ]
Map { { n: 1 } => 'A', '2' => 9 }
2複製程式碼

從上述程式碼中,我們可以看出使用new Map()語法進行宣告,map鍵的型別可以使用任意物件作為鍵(字串,object型別,functions),我們直接二維陣列鍵值對的形傳入到構建函式中,第一項為鍵,後一項為值。

const map=new Map([['foo',1],['foo',2]])
console.log(map);
console.log(map.get('foo'))複製程式碼

上述程式碼將會輸出:

Map { 'foo' => 2 }
2複製程式碼

上述程式碼我們可以看出,如果存在相同的鍵,則會按照FIFO(First in First Out,先進先出)原則,後面的鍵值資訊會覆蓋前面的鍵值資訊。

Map常用方法示例

以下表格羅列了Map相關的方法

操作方法

內容描述

map.set(key,value)

新增鍵值對到對映中

map.get(key)

獲取對映中某一個鍵的對應值

map.delete(key)

將某一鍵值對移除對映

map.clear()

清空對映中所有鍵值對

map.entries()

返回一個以二元陣列(鍵值對)作為元素的陣列

map.has(key)

檢查對映中是否包含某一鍵值對

map.keys()

返回一個當前對映中所有鍵作為元素的可迭代物件

map.values()

返回一個當前對映中所有值作為元素的可迭代物件

map.size

對映中鍵值對的數量

增刪鍵值對與清空MAP

let user={name:"Aaron",id:1234};
let userHobbyMap=new Map();
userHobbyMap.set(user,['Ice fishing','Family Outting']);//新增鍵值對
console.log(userHobbyMap);
userHobbyMap.delete(user);//刪除鍵值對
userHobbyMap.clear(); //清空鍵值對
console.log(userHobbyMap);複製程式碼

上述程式碼將會輸出:

Map { { name: 'Aaron', id: 1234 } => [ 'Ice fishing', 'Family Outting' ] }
Map {}複製程式碼

獲取鍵值對

與Set集合物件不一樣,集合物件的元素沒有元素位置的標識,故沒有辦法獲取集合某元素,但是對映物件由鍵值對組成,所以可以利用鍵來獲取對應的值。

const map=new Map();
map.set('foo', 'bar');
console.log(map.get('foo')); //output bar複製程式碼

檢查對映物件中是否存在某鍵

與Set集合一樣,Map對映也可以使用has(鍵)的方法來檢查是否包含某鍵。

const map=new Map([['foo',1]])
console.log(map.has('foo'));//output true
console.log(map.has('bar'));//output false複製程式碼

遍歷對映中的鍵值對

對映物件在設計上同樣也是一種可迭代的物件,可以通過for-of迴圈對其遍歷,同時也可以使用foreach進行遍歷。 對映物件中帶有entries()方法,用於返回包含所有鍵值對的可迭代的二元陣列物件,而for-of和foreach便是先利用entries()方法先將對映物件轉換成一個類陣列物件,然年再進行迭代。

const map=new Map([['foo',1],['bar',2]]);
console.log(Array.from(map.entries()));
//output
//[ [ 'foo', 1 ], [ 'bar', 2 ] ]
for(const [key,value] of map){
    console.log(`${key}:${value}`);
}
//output
//foo:1
//bar:2
map.forEach((value,key,map)=>
  console.log(`${key}:${value}`))
//output
//foo:1
//bar:2複製程式碼

Map與Object的區別

說了這麼多對映物件的方法,Map和Object物件有哪些區別呢,以下表格進行了總結:

對比項

對映物件Map

Object物件

儲存鍵值對

遍歷所有的鍵值對

檢查是否包含指定的鍵值對

使用字串作為鍵

使用Symbol作為鍵

使用任意物件作為鍵

可以很方便的得知鍵值對的數量

從中我們可以看出Map物件可以使用任何物件作為鍵,這就解決了我們實際應用中一個很大的痛點,比如現在一個DOM物件作為鍵時,Object就不是那麼好用了。

WeakMap

與集合型別(Set)一樣,對映型別也有一個Weak版本的WeakMap。WeakMap和WeakSet很相似,只不過WeakMap的鍵會檢查變數的引用,只要其中任意一個引用被釋放,該鍵值對就會被刪除。

以下三點是Map和WeakMap的主要區別: 1.Map物件的鍵可以是任何型別,但WeakMap物件中的鍵只能是物件引用 2.WeakMap不能包含無引用的物件,否則會被自動清除出集合(垃圾回收機制)。 3.WeakSet物件是不可列舉的,無法獲取大小。

下段程式碼示例驗證了WeakMap的以上特性:

let weakmap = new WeakMap();
(function(){ 
  let o = {n: 1}; 
  weakmap.set(o, "A");
})();  // here 'o' key is garbage collected
let s = {m: 1};
weakmap.set(s, "B");
console.log(weakmap.get(s));
console.log(...weakmap); // exception thrown
weakmap.delete(s);
weakmap.clear(); // Exception, no such function
let weakmap_1 = new WeakMap([[{}, 2], [{}, 5]]); //this works
console.log(weakmap_1.size); //undefined”複製程式碼
const weakmap=new WeakMap();
let keyObject={id:1};
const valObject={score:100};
weakmap.set(keyObject, valObject);
console.log(weakmap.get(keyObject));
//output { score: 100 }
keyObject=null;
console.log(weakmap.has(keyObject));
//output false複製程式碼

小節

今天的內容就介紹到這裡,我們明白了Map是一個鍵值對的對映物件,相比Object來說可以使用任何鍵做為鍵值,並且能夠很方便的獲取鍵值對。WeakMap相對於Map是一個不可列舉的物件,必須使用物件作為鍵值。如何更好的使用Map和WeakMap還需要具體結合我們實際的業務場景進行靈活使用。


相關文章