[筆記] 理解 Set(集合) & WeakSet(弱集合)

Set


  • 可以儲存任何類型的唯一值,不論型別或物件

    1
    2
    3
    4
    5
    6
    new Set([iterable]);

    const set = new Set([1, 2, 3, 4, 4]);
    //去除重複成員的寫法
    Array.from( set ) // 1,2,3,4
    [ ...set ] // 1,2,3,4
  • add

    • 替 Set 新增一個值並回傳 Set Object

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22

      let mySet = new Set();
      mySet.add('1'); // String
      mySet.add(2); // Number

      let obj = {key:'hello'};

      mySet.add(obj); // Object

      mySet.add(obj); //因obj是參考同一個物件,因此會被濾掉

      mySet.add({key:'hello'}); //和obj是參考不同的物件,所以這個可以被Set新增

      mySet.add({key:'hello'}); //同上,因為是全新的一個參考,所以這個也會被Set新增

      let a = NaN;
      let b = NaN;
      mySet.add(a);
      mySet.add(b); // Set 判斷 NaN 是相等的

      mySet.forEach(item=>console.log(item));
      // "1" , 2 , { key: "hello" } , { key: "hello" } , { key: "hello" } , NaN
  • size

    • 返回Set值的總數量 mySet.size ; // 6
  • delete

    • 刪除Set的某個值,返回布林值,true代表刪除成功

      1
      2
      const set = new Set([1, 2, 3, 4, 4]);
      set.delete(1); // true
  • has

    • 返回布林值,判斷是否為Set值

      1
      2
      3
      4
      5
      6
      7
      let mySet = new Set([1,4]);

      var o = {a: 1, b: 2};
      mySet.add(o);
      mySet.has(1); // true
      mySet.has(3); // false
      mySet.has(o); // true
  • clear

    • 刪除Set所有值,不會返回值 mySet.clear() ;

Set 迭代

  1. keys()
  2. values()
  3. entries()
  4. forEach()
  • keys方法和values方法的行為完全一樣
  • entries 會返回鍵名與鍵值,且完全一樣

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    let set = new Set(['A', 'B', 'C']);

    for (let item of set.keys()) {
    console.log(item);
    }
    // A
    // B
    // C

    for (let item of set.values()) {
    console.log(item);
    }
    // A
    // B
    // C

    for (let item of set.entries()) {
    console.log(item);
    }
    // ["A", "A"]
    // ["B", "B"]
    // ["C", "C"]
  • 根據已上結論,直接使用for of 遍歷 Set 即可

    1
    2
    3
    for (let item of set) {
    console.log(item);
    }
  • forEach

    • 因Set沒有索引值,所以參數value與key是一樣的(如下範例
    • 值得注意的是,若值為 undefined 還是可以被遍歷出來的
    • 參考:Set.prototype.forEach()

      1
      2
      3
      4
      5
      6
      set = new Set([1, 4, 9 , undefined]);
      set.forEach((value, key) => console.log(key + ' : ' + value))
      // 1 : 1
      // 4 : 4
      // 9 : 9
      // undefined : undefined
  • Set 除了過濾重複值,也可以很容易的實現 聯集(Union)、交集(Intersect)和差集(Difference)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let a = new Set([1, 2, 3]);
    let b = new Set([4, 3, 2]);

    // 聯集
    let union = new Set([...a, ...b]);
    // Set {1, 2, 3, 4}

    // 交集
    let intersect = new Set([...a].filter(x => b.has(x)));
    // set {2, 3}

    // 差集
    let difference = new Set([...a].filter(x => !b.has(x)));
    // Set {1}

改變Set結構

1
2
3
4
5
6
7
8
9
// 方法一
let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
// set的值是2, 4, 6

// 方法二
let set = new Set([1, 2, 3]);
set = new Set(Array.from(set, val => val * 2));
// set的值是2, 4, 6

WeekSet

  • WeekSet 是對象值的集合,每個對象值只能出現一次
  • 只能儲存對象引用,不能像Set一樣存放值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    new WeakSet([iterable]);

    const a = [[1, 2], [3, 4]];
    const ws = new WeakSet(a);
    // WeakSet {[1, 2], [3, 4]}

    const b = [3, 4];
    const ws = new WeakSet(b);
    // Uncaught TypeError: Invalid value used in weak set(…)
  • add

    • 替 WeekSet 新增一個對象 Weakly link an object into the set
  • delete

    • 清除 WeekSet 的某個對象 Remove a link to an object from the set
  • has

    • 檢查 WeekSet 是否存在某個對象 Check if an object has already been linked to the set
  • clear ps.MDN上把clear方法列為瀏覽器不支援項目了

    • 清除 WeekSet 『所有』對象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var ws = new WeakSet();
    var window = {};
    var foo = {};

    ws.add(window);
    ws.add(obj);

    ws.has(window); // true
    ws.has(foo); // false foo不是ws成員

    ws.delete(window);
    ws.has(window); // false, window 已經被移除
  • WeekSet沒有Size屬性

  • WeekSet沒有辦法遍歷它的值,因為內部資料隨時可能消失,遍歷機制無法保證資料存在。

    1
    2
    ws.size // undefined
    ws.forEach // undefined
  • what is WeakSet for?


總結

  • Set

    1. 也可是迭代
    2. 建構子也可以接受一個可迭代物件傳入
    3. 具有size屬性
    4. 值可以是任意值或物件參考
    5. 值必須唯一
    6. 中 NaN === NaN
    7. 沒有鍵/值,它是一維的,可視為陣列,只是值不會重複
  • WeekSet

    1. 無法進行迭代,但建構子可接受一個可迭代物件傳入

參考資料來源

  1. Set 和 Map 数据结构
  2. MDN - Set
  3. MDN - WeekSet