ES6專欄 - 新的數據結構Set

ES6 - 新的數據結構Set

目錄:

  • 基本用法

  • Set實例的方法和屬性

之前筆者寫過, ES6給我們提供了一種新的數據結構Symbol, 而Set也是Es6給我們提供的新的數據結構, 他類似於數組, 但跟數組不同的是, Set這哥們所有的成員都是唯一的, 不可能出現重複

基本用法

Set本身是一個構造函數, 可以用來直接生成Set數據結構

const fstSet = new Set();
console.log(fstSet); // Set(0) {}

const secSet = new Set([1, 2, 3, 4, 5]);
console.log(secSet); // Set(5) {1, 2, 3, 4, 5}

const trdSet = new Set([1, 2, 2, 3, 4]);
console.log(trdSet); // Set(4) {1, 2, 3, 4}

我們上面可以發現, 由於Set不允許出現重複值, 所以在trdSet中, 數據被自動去重了

一個Set結構的真實數據結構如下

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9QFsaJwP-1583379124293)('...')]

Set函數可以接收一個數組(或者其他具有iterable接口的數據結構)作爲參數, 用來初始化

iterable接口 - 迭代接口, 在後面的文章中會詳細介紹, 這裏混個臉熟

比如也可以使用字符串對Set進行初始化

const strSet = new Set('helloWorld');
console.log(strSet); // Set(7) {"h", "e", "l", "o", "W", "o", "r", "l", "d"}

小技巧

既然Set結構不允許出現重複值, 同時又可以接收數組作爲參數進行初始化, 那我們勢必可以利用這個特性做數組去重

const fstArr = [1, 2, 2, 3, 4, 2];
const obj = {
    name: 'loki',
    age: 18
}
const secArr = [obj, obj];

// 之前筆者寫過spread擴展運算符可以展開一切具有迭代接口的數據, 而Set結構也具有迭代接口
const newFstArr = [...new Set(fstArr)];
const newSecArr = [...new Set(secArr)];
console.log(newFstArr); // [1, 2, 3, 4]
console.log(newSecArr); // [{name: 'loki', age: 18}]

Set上的實例方法和屬性

Set結構的實例擁有以下屬性:

  • Set.prototype.constructor: 該實例的構造函數, 默認是Set函數

        const fstSet = new Set([1, 2, 3, 4]);
        console.log(fstSet.constructor); // function Set() {}
    
  • Set.prototype.size: 類似於數組的length, 返回Set實例成員總量

        const secSet = new Set([1, 2, 3, 4]);
        console.log(secSet.size); // 4
    

Set實例的方法分爲兩大類, 操作方法和遍歷方法

  1. 操作方法

    • Set.prototype.add(value): 給該Set實例添加某個值, 功能類似於數組的push, 該方法執行完畢以後返回該Set實例

          const fstSet = new Set([1, 2]);
          fstSet.add(3);
          console.log(fstSet); // Set(3) {1, 2, 3}
          fstSet.add(2); 
          console.log(fstSet); // Set(3) {1, 2, 3}
      

      既然返回的是該Set實例, 則代表該方法可以進行鏈式調用

          const fstSet = new Set([1]);
          fstSet.add(1).add(2).add(3).add(3);
          console.log(fstSet); // Set(3) {1, 2, 3}
      
    • Set.prototype.delete(value): 給該Set實例刪除某個值, 該方法返回一個布爾值, 表示是否成功

          const fstSet = new Set([1, 2]);
          fstSet.delete(2);
          console.log(fstSet); // Set(1) {1}
      
    • Set.prototype.has(value): 該方法用來驗證一個值是否爲Set結構的成員

          const fstSet = new Set(['loki', 'thor']);
          console.log(fstSet.has('loki')); // true
          console.log(fstSet.has('andy')); // false
      
    • Set.prototype.clear(): 直接清除所有成員, 不提供任何返回值

          const fstSet = new Set(['loki', 'thor']);
          fstSet.clear();
          console.log(fstSet); // Set(0) {}
      

      小技巧

      上面筆者說過我們用spread擴展運算符可以擴展Set結構,從而我們可以將Set結構轉化爲數組 而筆者在數組得擴展中也提到過Array.from方法, 該方法也可以將Set結構轉化爲數組

          const fstSet = new Set([1, 2, 3]);
          const newArr = Array.from(fstSet);
          console.log(newArr); // [1, 2, 3]
      
  2. 遍歷方法

    • Set.prototype.keys(): 返回該Set實例的key, 這些key會放在一個遍歷器中, 我們可以通過next方法一個一個去取它key對應的值, 也可以通過for...of方法進行遍歷

      至於遍歷器, 你當下也不需要太過於清晰, 後面筆者會專門寫道, 但是你現在要知道有這麼個方法, 混個臉熟, 等對迭代器的知識懂一些了其實就完全通透了, 到時候再回來看看絕對有大收穫, 你唯一要注意的是next方法執行依次, 遍歷器中的值就會被順走一個, 所以for…of和next方法不能同時存在, 否則很尷尬

          const fstSet = new Set(['loki', 'thor']);
          const setIterator = fstSet.keys();
          console.log(setIterator); // SetIterator {"loki", "thor"}   
      
          for(let item of setIterator) {
              console.log(item); // 依次輸出loki, thor
          }
      
          console.log(setIterator); // SetIterator {}
      
    • Set.prototype.values(): 返回該Set實例的value遍歷器

          const fstSet = new Set(['loki', 'thor']);
          const setValueIterator = fstSet.values(); 
          console.log(setValueIterator); // setIterator {"loki", "thor"}   
          console.log(setValueIterator.next()); // {value: "loki", done: false}
          console.log(setValueIterator.next()); // {value: "thor", done: false}
      

    小提示

     > 由於Set結構沒有鍵名, 只有鍵值,或者說Set結構的鍵名和鍵值爲同一個值 所以Set.prototype.keys和Set.prototype.values返回的值完全一致
    
    • Set.prototype.Entries(): 返回該Set實例鍵值對的遍歷器

          const fstSet = new Set(['loki', 'thor']);
          const setEntriesIterator = fstSet.entries(); 
          console.log(setEntriesterator); // SetIterator {"loki" => "loki", "thor" => "thor"}  
          console.log(setEntriesIterator.next()); // {value: ["loki", "loki"], done: false}
          console.log(setEntriesIterator.next()); // {value: ["thor", "thor"], done: false}
      
          <!-- 上面的這兩個loki和兩個thor實際上是系統強制給他添加的key和value爲同一值 -->
      
    • Set.prototype.forEach(): 使用回調函數遍歷Set實例的每個成員,跟數組的forEach完全一致, 該方法接收兩個參數

      • 回調函數(key, value, el)

        • key: 鍵名

        • value: 鍵值

        • el: 該Set實例自身

      • this指向: 設置當前遍歷期間該方法的this指向, 注意如果沒有使用第二個參數或者寫了第二個參數但是第一個參數使用的爲箭頭函數, 這兩種情況下, this指向window

          const fstSet = new Set(['loki', 'thor'])
          fstSet.forEach(function(key, value, el) {
              console.log(this); // {name: '我是新的this指向'}
              console.log(key, value, el); // loki loki Set(2) {"loki", "thor"}
          }, {name: '我是新的this指向'})
      

    小技巧

    使用Set我們可以很輕易的實現交集, 並集和差集, 因爲Set不允許重複值存在

    • 並集

       let fstSet = new Set([1, 2, 3]);
       let secSet = new Set([2, 3, 4]);
       // 將這兩哥們展開就行了, 或者Array.from, 然後又放進一個新的set結構中
       let trdSet = new Set([...fstSet, ...secSet]);
      
       console.log(trdSet); // Set(4) {1, 2, 3, 4}
      
    • 交集

       let fstSet = new Set([1, 2, 3]);
       let secSet = new Set([2, 3, 4]);
       
       // 我們直接將第一個Set結構轉化爲數組, 然後用第二個Set結構的has方法來匹配, 匹配爲真就是交集
      
       let trdSet = new Set([...fstSet].filter(el => secSet.has(el)));
       console.log(trdSet); // Set(2) {2, 3}
      
    • 差集

       let fstSet = new Set([1, 2, 3]);
       let secSet = new Set([2, 3, 4]);
       
       // 那不是交集不就是差集嘍
      
       let trdSet = new Set([...fstSet].filter(el => !secSet.has(el)));
       console.log(trdSet); // Set(2) {1, 4}
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章