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還需要具體結合我們實際的業務場景進行靈活使用。