ES6 新增數據結構,太強了,值得學習
大家好,我是前端人,每日分享前端相關內容!
今天給大家介紹下 ES6 中的 Map、WeakMap、set 和 WeakSet 的詳細使用,以及它們的區別!
本篇文章知識點總結如下:
一、Set
ES6 中提供新的數據結構 Set 集合,它類似于數組,但成員的值都是唯一的,集合類似于高中所學的集合,概念是一致的。集合實現了 iterator 接口,所以他可以使用擴展運算符進行展開,也可以使用 for...of 進行遍歷。
set 使用:
let s = new Set([ '年終獎是大事', '放假是好事', '放假是好事' ]);
console.log( s ) // set(2) { '年終獎是大事', '放假是好事' }
console.log( typeof s ) // object
new Set 返回的數據是一個對象,它是自動去掉重復項。
集合的屬性和方法分別有:
- size :返回集合元素的個數
- add :增加一個新元素
- delete:刪除某個元素,返回布爾值
- has :檢測集合中是否包含某元素
- clear:清空集合
Set 的常見應用:
數組去重:
let arr = [ 1,2,3,4,3,2,1 ]
let res = [ ...new Set(arr) ]
console.log( res ) //[1, 2, 3, 4]
取兩個集合的交集
let arr1 = [ 1,2,3,4,3,2,1 ]
let arr2 = [ 1,2 ]
let res = [...new Set(arr1)].filter( item=>new Set(arr2).has(item) )
console.log( res ) //[1, 2]
取兩個集合的并集
let arr1 = [ 1,2,3,4,3,2,1 ]
let arr2 = [ 1,2 ]
let res =[ ...new Set([...arr1, ...arr2]) ]
console.log(res ) //[ 1, 2, 3, 4 ]
取差集
let arr1 = [ 1,2,3,4,3,2,1 ]
let arr2 = [ 1,2 ]
let res = [...new Set(arr1)].filter( item=>!new Set(arr2).has(item) )
console.log( res ) //[ 3, 4 ]
Set 數據遍歷:
let s1 = new Set()
s1.add("碧根果")
s1.add("夏威夷果")
for(let v of s1){
console.log("v",v)
}
/*
v 碧根果
v 夏威夷果
*/
Set 遍歷的方式有很多,我只介紹 for...of ,剩余的可自行查找!
二、Map
ES6 提供了 Map 數據結構,它類似于對象,也是鍵值對的集合,但是鍵的范圍不限于字符串,各種類型的值(包括對象)都可以當做鍵,Map 也實現了 iterator 接口,所以也可以使用 for...of 進行遍歷,使用擴展運算符展開數據。
Map 的使用:
let m= new Map()
m.set( "name", "我是前端人" )
let key = {
job: "前端工程師"
}
m.set( key, [ "運營", "設計" ] )
console.log(m)
運行結果如圖:
集合的屬性和方法:
- size :返回集合元素的個數
- set:給 Map 添加鍵值對。
- get:從 Map 中提取值。
- delete:刪除某個元素,返回布爾值
- has :檢測集合中是否包含某元素
- clear:清空集合
Map 的遍歷
let map = new Map([['title','hello world'],['year','2022']]);
map.forEach((value,key,ownerMap)=>{
console.log(value);
console.log(key);
});
hello world
title
2022
year
Map 的應用
假設有一個場景,我們需要存儲 DOM 節點的屬性以及它的值,我們可能會用到 Object 或者 Map 。在這選擇 Map
const m = new Map()
const loginBtn = document.querySelector("#login")
m.set( loginBtn, { disabled: true } )
這樣應用的時候會產生一個問題:當用戶登錄之后,跑到另一個界面,登錄按鈕被移除,正常來說,這個 DOM 節點應該被垃圾回收清除,但是它被 loginBtn 變量引用,loginBtn 作為 key 被 Map 引用,所以登錄 DOM 節點會保留在內存中,白白占用空間。此時就需要引入 WeakMap 。
三、WeakMap
WeakMap 的 key 只能是 Object 實例化的對象或者派生類的對象,如果不是的話,則會報錯,WeakMap 對象的 value 值 可以是任意類型數據。
WeakMap 使用
let wm = new WeakMap()
wm.set( {},'value' )
弱鍵:WeakMap 的 key 都是對象或者派生類的對象,目的是為了讓這個 key 被弱持有。這些對象都是弱引用,不會干擾到垃圾回收。當 WeakMap 中的鍵在 WeakMap 之外不存在引用時,該鍵值對會被移除。
Map 中的實例把 Map 替換成 weakMap:
const vm = new WeakMap()
const loginBtn = document.querySelector("#login")
vm.set( loginBtn, { disabled: true } )
作為 WeakMap 對象的 key 不會被正式引用,也就是說 loginBtn 變量不被 vm 引用,這時垃圾回收器就可以把這個 loginBtn 變量和登錄DOM節點都給干掉,釋放內存空間。
WeakMap 的 key 不算正式引用,隨時可以被回收清除掉,因此 WeakMap 不提供迭代功能。對于 size 屬性和 clear 方法,由于它們需要先迭代遍歷所有的 key 才能計算得到,所以 size 和 clear 無法使用。
WeakMap 的 API 與 Map 對象基本都是一樣的,除了沒有 size 屬性和 clear 方法。
四、WeakSet
WeakSet 對于 Set 而言,就像 WeakMap 對于 Map 一樣。
在存放對象時,實際上是存放的是對象的引用,即 Set 也被稱之為 Strong Set 。如果所存儲的對象被置為 null ,但是 Set 實例仍然存在的話,對象依然無法被垃圾回收器回收,從而無法釋放內存。
let set = new WeakSet();
let key = {};
set.add(key);
console.log(set.has(key)); //true
set.delete(key);
console.log(set.has(key)); //false
注意:WeakSet 構造器不接受基本類型的數據,只接受對象。同樣的可以使用可迭代的對象或數組,來作為構造器參數,來創建 WeakSet 。
WeakSet 的 API 與 Set 對象基本都是一樣的,除了沒有 size 屬性和 clear 方法。
五、總結之間的區別
5.1、對于 WeakSet 和 Set 之間的區別:
WeakSet 沒有 size 和 clear 。
- WeakSet 無法暴露出任何迭代器。
- WeakSet 不可迭代,因此不能使用 for...of 遍歷
- WeakSet 實例,弱調用了 add 方法時傳入非對象參數,會拋出異常。在 has 和 delete 方法傳入非對象的參數返回 false。
對于 WeakMap 和 Map 之間的區別與上邊 WeakSet 和 Set 的區別類似。不再贅述。
5.2、Set 與 Map 之間的共性及區別:
- Set 和 Map 都是一種數據結構,但是 Set 是一個無重復的有序列表,類似于數組,而 Map 是有序的鍵值對集合,類似于對象。
- 都將通過 Object.is() 方法來判斷其中的值不相等,保證 Set 和 Map 移除重復值。Set 無法隨機訪問其中的值,只能通過 has 判斷某個值是否存在。而 Map 使用 get 提取任意鍵對應的數據。
- Map 和 Set 都可以隨意的實例中添加數據,Set 使用的是 add ,而 Map 使用的 set 方法。其他的 API 都相同。