1. 程式人生 > 程式設計 >ES6中Set與WeakSet集合的深入講解

ES6中Set與WeakSet集合的深入講解

目錄
  • Set是值永不重複的特殊集合
  • Set集合基礎API
    • 關於唯一值的判斷
    • Set集合遍歷的3種方式
  • Set集合案例實踐
    • Set集合與Array陣列之間的轉換
    • 單個數組去重
    • 多個數組合並去重
    • 獲取交集(重複的元素)
    • 判斷是否有交集(重複的元素)
    • 獲取差集:只返回重複
  • WeakSet“弱”在哪裡?
    • 弱功能
    • 弱引用
  • 總結

    Set是值永不重複的特殊集合

    每天都用陣列,有沒有過一個Moment,擔心插入了重複的值?使用Set集合吧!Set擁有特殊的資料結構,保證插入的值永遠不會重複。

    Set集合基礎API

    通過Set.prototype.constructor 建構函式建立Set例項

    /*
     * 僅例項化:呼叫建構函式,不傳引數
     */ 
    let empty_set = new Set()    
    
    
    /*
     * 例項化同時初始化:傳入任意iterate物件,將其轉換成Set集合
     */ 
    let transfer_set4arr = new Set([1,2,3])
    // 返回Set(3){1,3}
    
    let transfer_set4string = new Set("huilin")
    // 返回Set(5){"h","u","i","l","n"}
    
    let transfer_set4set = new Set(new Set([5,6]))
    // 返www.cppcns.com
    回Set(2) { 5,6 }

    訪問 Set.prototype.size屬性,返回集合中元素的個數

    console.log(empty_set.size) // 0
    console.log(transfer_set4arr.size)  // 3
    

    呼叫 Set.prototype.has(value) 方法,判斷元素是否存在

    // 相比起Array.includes(),Set.has()效能更高,因為專門對成員測試進行了優化
    console.log(empty_set.has(1))   // false
    console.log(transfer_set4arr.has('h')) // true
    

    關於唯一值的判斷

    • Set集合為確保值的唯一性,使用Object.is(value1,value2)進行判斷,而不是通過===(恆等符號)符號來判斷的,因為恆等判斷會將兩邊的變數進行強制型別轉換。
    • 比如,兩個變數的值均為NaN,或者0和-0,用判斷是不相等的,但Object.is()認為是同一個只,因此不能存入Set集合中。

    想了解更多關於Object.is(),請跳轉檢視:developer.mozilla.org/zh-CN/docs/…

    let n1 = NaN
    let n2 = NaN
    
    console.log(n1 === n2)  
    // 恆等符號判斷兩者不一致,輸出false
    
    console.log(Object.is(n1,n2)) 
    // 但Object.is()判斷兩者是相同的,輸出false
    
    // Set集合不允許將兩個NaN放入集合
    let set = new Set()
    set.add(n1).add(n2)
    console.log(set.size)   
    // size: 1
    

    而面對複雜資料型別時,主要通過物件的引用進行判斷。引用不一致,即便資料結構一致,也認為只不相同,因此能存入Set集合。

    let same_value_set = new Set();
    // 先存入一個物件
    same_value_set.add({num: 0});
    // 再存入一個結構一致的新物件
    let obj = {num: 0};
    same_value_set.add(obj);
    // 都能存入成功
    console.log(same_value_set.size); // 2
    

    呼叫Set.prototype.add(value) 方法,向集合追加資料

    // add()方法可以追加任意型別的資料,不論是原始值或者是物件引用
    
    let set1 = new Set()
    // 由於add()方法始終返回當前例項的引用,所以進行鏈式呼叫
    set1.add(1).add(2).add(3)
    console.log(set1) // Set(3){1,3}
    
    // 注意:當add()傳入陣列時,Set會將陣列例項插入集合,而不是陣列內的元素
    set1.add([4,5])
    console.log(set1) // Set(4) {1,3,[4,5]}
    www.cppcns.com

    呼叫Set.prototype.delete(value) 方法,移除集合中的元素

    // delete()方法返回移除操作是否成功,與.has()方法一樣
    let success = set1.delete(1)
    console.log(success)
    // true
    

    呼叫Set.prototype.clear() 方法,清空集合

    let num_set = new Set([1,6,3])
    console.log(num_set)
    // Set(3) { 1,3 }
    
    set1.clear()
    console.log(num_set)
    // Set(0) {}
    

    Set集合遍歷的3種方式

    由於集合沒有下標/索引,通常被認為是“無序集合”。但會記住元素插入的順序,所以遍歷的時候也按順序對元素進行迭代。

    直接遍歷Set集合

    let set = new Set([1,4,5])
    for(let item of set){
        console.log(item)
    }
    // 依次輸出:1 2 3 4 5
    

    建立迭代器進行遍歷

    /*
     * 建立迭代器的有三種方式
     * Set.prototype.entries()
     * Set.prototype.keys()
     * Set.prototype.values()
     */ 
    
    // Set集合只有value而沒有key,但為了使得和遍歷Map物件相似,Set.entries()建立新的Iterator物件時,每一項的鍵和值都相等,即[value,value]
    for(let [key,value] of set.entries()){
        console.log(value)
    }
    // 依次輸出:1 2 3 4 5
    
    // Set.keys()建立新的Iterator物件,返回每一項值
    for(let key of set.keys()){
        console.log(key)
    }
    // 依次輸出:1 2 3 4 5
    
    // Set.values()和Set.keys()一致,返回每一項的值
    for(let value of set.values()){
        console.log(value)
    }
    // 依次輸出:1 2 3 4 5
    

    呼叫Set.prototype.forEach(callbackFn)方法遍歷

    // forEach(callbackFn) 按照插入順序呼叫callbackFn,取出每項值
    set.forEach(item => {
        console.log(item)
    })
    // 依次輸出:1 2 3 4 5
    

    Set集合案例實踐

    Set集合與Array陣列之間的轉換

    /*
     * Set轉Array
     */
    let set1 = new Set([1,3])
    // Array.from()方法
    let arr1 = Array.from(set1)  
    // 擴充套件運算子
    let arr2 = [...set1]  
    
    /*
     * Array轉Set
     */
     // 利用Set建構函式
    let set = new Set(array)
    

    單個數組去重

    let setwww.cppcns.com = new Set([1,5])
    console.log(set)
    // Set(4) { 1,5 }
    

    多個數組合並去重

    let arr1 = [1,4]
    let arr2 = [1,5,6]
    
    // 利用Set集合的特性,集合內的元素都是唯一的
    let result = new Set([...set1,...set2]) 
    console.log(result)
    // Set(5) { 1,6 }
    

    獲取交集(重複的元素)

    let set1 = new Set([1,4])
    let set2 = new Set([1,6])
    
    // 返回set1和set2都存在的元素
    let result = new Set([...set1].filter(x => set2.has(x))) 
    console.log(result)
    // Set(1) { 1 }
    

    判斷是否有交集(重複的元素)

    let set1 = new Set([1,6])
    
    function isMixed(set,subset) {
        for (let elem of subset) {
            if (set.has(elem)) {
                return true;
            }
        }
        return false;
    }
    
    console.log(isMixed(set1,set2))
    // true
    

    獲取差集:只返回重複

    let set1 = new Set([1,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不允許插入原始值,僅支援物件的引用;

    let val1 = {id: 1},val2 = {id: 2}
    
    let ws = new WeakSet()
    
    // 和Set集合一樣,WeakSet的值也不重複,同時add()也返回集合例項,所以可以鏈式操作
    ws.add(val1).add(val1).add(val2)
    
    // 不允許插入基礎資料型別
    ws.add(3)
    // 報錯:TypeError:Invalid value used in WeakSet
    
    // 但可以先包裝成物件後再插入
    let val3 = new Number(3)
    ws.add(val3)
    console.log(ws.has(val3))
    // 輸出:true
    
    
    • WeakSet僅實現了add()、has()、delete()三個操作方法;
    • WeakSet不允許遍歷,也沒有size或者length屬性;

    弱引用

    要說弱引用,先看看什麼是強引用:

    // 宣告一個物件
    let handsome = {
        name: 'huilin',age: 30
    }
    
    // 放入陣列
    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('----')
    
    // 突然把物件置為null
    handsome = null
    // 強引用的容器中,物件仍然存在沒有被回收
    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 }
    

    從測試程式碼看出,除非容器銷燬,否則引用的物件一直沒有被回收。而所謂弱引用,就是希望容器是根據元素自動伸縮的,一旦物件為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
    
    // 或者是物件自己置為null,都會自動回收
    obj2 = null
    console.log(ws1.has(obj2))  // false
    

    Reference

    • zh.script.info/map-set
    • es6.ruanyifeng.com/#docs/set-m…

    總結

    到此這篇關於ES6中Set與WeakSet集合的文章就介紹到這了,更多相關ES6 Set與WeakSet集合內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!