ES6中Set與WeakSet集合的深入講解
Set是值永不重復(fù)的特殊集合
每天都用數(shù)組,有沒(méi)有過(guò)一個(gè)Moment,擔(dān)心插入了重復(fù)的值?使用Set集合吧!Set擁有特殊的數(shù)據(jù)結(jié)構(gòu),保證插入的值永遠(yuǎn)不會(huì)重復(fù)。
Set集合基礎(chǔ)API
通過(guò)Set.prototype.constructor 構(gòu)造函數(shù)創(chuàng)建Set實(shí)例
/*
* 僅實(shí)例化:調(diào)用構(gòu)造函數(shù),不傳參數(shù)
*/
let empty_set = new Set()
/*
* 實(shí)例化同時(shí)初始化:傳入任意iterate對(duì)象,將其轉(zhuǎn)換成Set集合
*/
let transfer_set4arr = new Set([1, 2, 3])
// 返回Set(3) {1, 2, 3}
let transfer_set4string = new Set("huilin")
// 返回Set(5) {"h", "u", "i", "l", "n"}
let transfer_set4set = new Set(new Set([5, 6]))
// 返回Set(2) { 5, 6 }
訪(fǎng)問(wèn) Set.prototype.size屬性,返回集合中元素的個(gè)數(shù)
console.log(empty_set.size) // 0 console.log(transfer_set4arr.size) // 3
調(diào)用 Set.prototype.has(value) 方法,判斷元素是否存在
// 相比起Array.includes(),Set.has()性能更高,因?yàn)閷?zhuān)門(mén)對(duì)成員測(cè)試進(jìn)行了優(yōu)化
console.log(empty_set.has(1)) // false
console.log(transfer_set4arr.has('h')) // true
關(guān)于唯一值的判斷
- Set集合為確保值的唯一性,使用Object.is(value1,value2)進(jìn)行判斷,而不是通過(guò)===(恒等符號(hào))符號(hào)來(lái)判斷的,因?yàn)楹愕扰袛鄷?huì)將兩邊的變量進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。
- 比如,兩個(gè)變量的值均為NaN,或者0和-0,用JS判斷是不相等的,但Object.is()認(rèn)為是同一個(gè)只,因此不能存入Set集合中。
想了解更多關(guān)于Object.is(),請(qǐng)?zhí)D(zhuǎn)查看:developer.mozilla.org/zh-CN/docs/…
let n1 = NaN let n2 = NaN console.log(n1 === n2) // 恒等符號(hào)判斷兩者不一致,輸出false console.log(Object.is(n1,n2)) // 但Object.is()判斷兩者是相同的,輸出false // Set集合不允許將兩個(gè)NaN放入集合 let set = new Set() set.add(n1).add(n2) console.log(set.size) // size: 1
而面對(duì)復(fù)雜數(shù)據(jù)類(lèi)型時(shí),主要通過(guò)對(duì)象的引用進(jìn)行判斷。引用不一致,即便數(shù)據(jù)結(jié)構(gòu)一致,也認(rèn)為只不相同,因此能存入Set集合。
let same_value_set = new Set();
// 先存入一個(gè)對(duì)象
same_value_set.add({num: 0});
// 再存入一個(gè)結(jié)構(gòu)一致的新對(duì)象
let obj = {num: 0};
same_value_set.add(obj);
// 都能存入成功
console.log(same_value_set.size); // 2
調(diào)用Set.prototype.add(value) 方法,向集合追加數(shù)據(jù)
// add()方法可以追加任意類(lèi)型的數(shù)據(jù),不論是原始值或者是對(duì)象引用
let set1 = new Set()
// 由于add()方法始終返回當(dāng)前實(shí)例的引用,所以進(jìn)行鏈?zhǔn)秸{(diào)用
set1.add(1).add(2).add(3)
console.log(set1) // Set(3) {1, 2, 3}
// 注意:當(dāng)add()傳入數(shù)組時(shí),Set會(huì)將數(shù)組實(shí)例插入集合,而不是數(shù)組內(nèi)的元素
set1.add([4, 5])
console.log(set1) // Set(4) {1, 2, 3, [4, 5]}
調(diào)用Set.prototype.delete(value) 方法,移除集合中的元素
// delete()方法返回移除操作是否成功,與.has()方法一樣 let success = set1.delete(1) console.log(success) // true
調(diào)用Set.prototype.clear() 方法,清空集合
let num_set = new Set([1, 6, 3])
console.log(num_set)
// Set(3) { 1, 6, 3 }
set1.clear()
console.log(num_set)
// Set(0) {}
Set集合遍歷的3種方式
由于集合沒(méi)有下標(biāo)/索引,通常被認(rèn)為是“無(wú)序集合”。但JavaScript會(huì)記住元素插入的順序,所以遍歷的時(shí)候也按順序?qū)υ剡M(jìn)行迭代。
直接遍歷Set集合
let set = new Set([1, 2, 3, 4, 5])
for(let item of set){
console.log(item)
}
// 依次輸出:1 2 3 4 5
創(chuàng)建迭代器進(jìn)行遍歷
/*
* 創(chuàng)建迭代器的有三種方式
* Set.prototype.entries()
* Set.prototype.keys()
* Set.prototype.values()
*/
// Set集合只有value而沒(méi)有key,但為了使得和遍歷Map對(duì)象相似,Set.entries()創(chuàng)建新的Iterator對(duì)象時(shí),每一項(xiàng)的鍵和值都相等,即[value,value]
for(let [key,value] of set.entries()){
console.log(value)
}
// 依次輸出:1 2 3 4 5
// Set.keys()創(chuàng)建新的Iterator對(duì)象,返回每一項(xiàng)值
for(let key of set.keys()){
console.log(key)
}
// 依次輸出:1 2 3 4 5
// Set.values()和Set.keys()一致,返回每一項(xiàng)的值
for(let value of set.values()){
console.log(value)
}
// 依次輸出:1 2 3 4 5
調(diào)用Set.prototype.forEach(callbackFn)方法遍歷
// forEach(callbackFn) 按照插入順序調(diào)用callbackFn,取出每項(xiàng)值
set.forEach(item => {
console.log(item)
})
// 依次輸出:1 2 3 4 5
Set集合案例實(shí)踐
Set集合與Array數(shù)組之間的轉(zhuǎn)換
/* * Set轉(zhuǎn)Array */ let set1 = new Set([1, 2, 3]) // Array.from()方法 let arr1 = Array.from(set1) // 擴(kuò)展運(yùn)算符 let arr2 = [...set1] /* * Array轉(zhuǎn)Set */ // 利用Set構(gòu)造函數(shù) let set = new Set(array)
單個(gè)數(shù)組去重
let set = new Set([1, 2, 4, 4, 2, 5])
console.log(set)
// Set(4) { 1, 2, 4, 5 }
多個(gè)數(shù)組合并去重
let arr1 = [1, 2, 4]
let arr2 = [1, 5, 6]
// 利用Set集合的特性,集合內(nèi)的元素都是唯一的
let result = new Set([...set1, ...set2])
console.log(result)
// Set(5) { 1, 2, 4, 5, 6 }
獲取交集(重復(fù)的元素)
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
// 返回set1和set2都存在的元素
let result = new Set([...set1].filter(x => set2.has(x)))
console.log(result)
// Set(1) { 1 }
判斷是否有交集(重復(fù)的元素)
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
function isMixed(set, subset) {
for (let elem of subset) {
if (set.has(elem)) {
return true;
}
}
return false;
}
console.log(isMixed(set1, set2))
// true
獲取差集:只返回重復(fù)
let set1 = new Set([1, 2, 4])
let set2 = new Set([1, 5, 6])
function difference(setA, setB) {
let result = new Set()
for (let elem of setB) {
if(setA.has(elem)){
result.add(elem)
}
}
return result;
}
console.log(difference(set1, set2))
WeakSet“弱”在哪里?
除了Set集合外,ES6還提供了WeakSet和WeakMap。既然集合的名字都叫“Weak(弱)的集合”了,究竟它“弱”在哪里呢?
弱功能
WeakSet不允許插入原始值,僅支持對(duì)象的引用;
let val1 = {id: 1},
val2 = {id: 2}
let ws = new WeakSet()
// 和Set集合一樣,WeakSet的值也不重復(fù),同時(shí)add()也返回集合實(shí)例,所以可以鏈?zhǔn)讲僮?
ws.add(val1).add(val1).add(val2)
// 不允許插入基礎(chǔ)數(shù)據(jù)類(lèi)型
ws.add(3)
// 報(bào)錯(cuò):TypeError:Invalid value used in WeakSet
// 但可以先包裝成對(duì)象后再插入
let val3 = new Number(3)
ws.add(val3)
console.log(ws.has(val3))
// 輸出:true
- WeakSet僅實(shí)現(xiàn)了add()、has()、delete()三個(gè)操作方法;
- WeakSet不允許遍歷,也沒(méi)有size或者length屬性;
弱引用
要說(shuō)弱引用,先看看什么是強(qiáng)引用:
// 聲明一個(gè)對(duì)象
let handsome = {
name: 'huilin',
age: 30
}
// 放入數(shù)組
let arr = [1, handsome, 2]
console.log('release before arr length', arr.length) // 3
// 放入Map
let user = {
oid: 10001,
classify: 'Chinese',
staffReference: handsome
}
console.log('release before map length', Object.keys(user).length) // 3
console.log('----')
// 突然把對(duì)象置為null
handsome = null
// 強(qiáng)引用的容器中,對(duì)象仍然存在沒(méi)有被回收
console.log('release after arr length', arr.length) // 3
console.log(arr[1]) // { name: 'huilin', age: 30 }
console.log('release after map length', Object.keys(user).length) // 3
console.log(user.staffReference) // { name: 'huilin', age: 30 }
從測(cè)試代碼看出,除非容器銷(xiāo)毀,否則引用的對(duì)象一直沒(méi)有被回收。而所謂弱引用,就是希望容器是根據(jù)元素自動(dòng)伸縮的,一旦對(duì)象為null,容器中的引用也跟著回收。
let obj1 = {
name: 'huilin',
age: 30
}
let obj2 = {
name: 'cc',
age: 29
}
let ws1 = new WeakSet()
ws1.add(obj1).add(obj2)
console.log(ws1.has(obj1)) // true
// 不管是從容器操作元素
ws1.delete(obj1)
console.log(ws1.has(obj1)) // false
// 或者是對(duì)象自己置為null,都會(huì)自動(dòng)回收
obj2 = null
console.log(ws1.has(obj2)) // false
Reference
總結(jié)
到此這篇關(guān)于ES6中Set與WeakSet集合的文章就介紹到這了,更多相關(guān)ES6 Set與WeakSet集合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript實(shí)現(xiàn)向setTimeout執(zhí)行代碼傳遞參數(shù)的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)向setTimeout執(zhí)行代碼傳遞參數(shù)的方法,分析了向setTimeout傳遞參數(shù)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04
javascript獲得服務(wù)器端控件的ID的實(shí)現(xiàn)代碼
javascript獲得服務(wù)器端控件的ID的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-12-12
js實(shí)現(xiàn)千分符和保留幾位小數(shù)的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇js實(shí)現(xiàn)千分符和保留幾位小數(shù)的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
淺談Webpack自動(dòng)化構(gòu)建實(shí)踐指南
本篇文章主要介紹了Webpack自動(dòng)化構(gòu)建實(shí)踐指南,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
純CSS3代碼實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)效果
CSS33D炫酷左右滑動(dòng)開(kāi)關(guān)按鈕是一款非??岬腃SS3 3D開(kāi)關(guān)按鈕,點(diǎn)擊按鈕可以左右滑動(dòng),就像開(kāi)關(guān)打開(kāi)閉合一樣的效果,通過(guò)本篇文章給大家介紹純CSS3代碼實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)效果,需要的朋友可以參考下2015-08-08
Bootstrap導(dǎo)航條可點(diǎn)擊和鼠標(biāo)懸停顯示下拉菜單的實(shí)現(xiàn)代碼
這篇文章主要介紹了Bootstrap導(dǎo)航條可點(diǎn)擊和鼠標(biāo)懸停顯示下拉菜單的實(shí)現(xiàn)代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06

