ES6

1.Set类型简介

ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

Set本身是一个构造函数,用来生成Set数据结构

1 const s = new Set();
2 [1,2,3,4,4,3,2,1].forEach( e => s.add(e))
3 
4 for(let i of s){
5     console.log(i);
6 }
7 // 1,2,3,4

 上面代码通过add()方法向Set结构加入成员,结果表明Set结构不会添加重复的值

Set函数可以接受一个数组(或者具有Iterable接口的其他数据结构)作为参数,用来初始化

 1 // 例一
 2 const set = new Set([1, 2, 3, 4, 4]);
 3 [...set]
 4 // [1, 2, 3, 4]
 5 
 6 // 例二
 7 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
 8 items.size // 5
 9 
10 // 例三
11 const set = new Set(document.querySelectorAll('div'));
12 set.size // 56
13 
14 // 类似于
15 const set = new Set();
16 document
17  .querySelectorAll('div')
18  .forEach(div => set.add(div));
19 set.size // 56

上面的办法展示了一种去除数组重复成员的方法:

const arr = [1,1,3,3,4,4,2]
const newArr = [...new Set(arr)]
newArr  // [1, 3, 4, 2]

或者也可以用于去除字符串里面的重复字符:

let str = "hello world"

let newStr = [...new Set(str.split(""))].join("")

newStr  // "helo wrd"

向Set加入值得时候,不会发生类型转换,所以 5 和 "5" 是两个不同的值。Set内部判断两个值是否不同使用的算法叫做'Same-Value-zero equality",它类似于精确相等运算符(===)。主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。

let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}

上面代码向 Set 实例添加了两次NaN,但是只会加入一个。这表明,在 Set 内部,两个NaN是相等的。

另外,两个对象总是不相等的。

let set = new Set()

set.add({})
set.add({})

set.size  // 2

上面代码表示,由于两个空对象不相等,所以它们被视为两个值。

2.Set实例的属性和方法

查看Set类型的原型对象可以看到Set结构的实例有以下属性。

(1)属性

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

(2)方法

Set实例的方法分为两大类:

  • 操作方法(用于操作数据)
    • Set.prototype.add(value):添加某个值,返回Set结构本身
    • Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功
    • Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员
    • Set.prototype.clear():清除所有成员,没有返回值
    • 实例:
      •  1 s.add(1).add(2).add(2);
         2 // 注意2被加入了两次
         3 
         4 s.size // 2
         5 
         6 s.has(1) // true
         7 s.has(2) // true
         8 s.has(3) // false
         9 
        10 s.delete(2);
        11 s.has(2) // false
  • 遍历方法(用于遍历成员)
    • Set.prototype.keys():返回键名的遍历器
    • Set.prototype.values():返回键值的遍历器
    • Set.prototype.entries():返回键值对的遍历器
      • 实例:
        •  1     let set = new Set(['red', 'green', 'blue'])
           2 
           3     for (let item of set.keys()) {
           4         console.log(item);
           5     }
           6     // red
           7     // green
           8     // blue
           9 
          10     for (let item of set.values()) {
          11         console.log(item);
          12     }
          13     // red
          14     // green
          15     // blue
          16 
          17     for (let item of set.entries()) {
          18         console.log(item);
          19     }
          20     // ["red", "red"]
          21     // ["green", "green"]
          22     // ["blue", "blue"]
      • 说明:entries方法返回的遍历器,同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等。
    • Set.prototype.forEach():使用回调函数遍历每个成员Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。注意:Set的遍历顺序就是插入顺序
    • 实例:
      • 1 let set = new Set([1, 4, 9]);
        2 set.forEach((value, key) => console.log(key + ' : ' + value))
        3 // 1 : 1
        4 // 4 : 4
        5 // 9 : 9
      • 上面代码说明,forEach方法的参数就是一个处理函数。该函数的参数与数组的forEach一致,依次为键值、键名、集合本身(上例省略了该参数)。这里需要注意,Set 结构的键名就是键值(两者是同一个值),因此第一个参数与第二个参数的值永远都是一样的。
    • 遍历方法的应用:
      • 扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。
        • let arr = [3, 5, 2, 2, 5, 5];
          let unique = [...new Set(arr)];
          // [3, 5, 2]
      • 数组的mapfilter方法也可以间接用于 Set 了。
        • let set = new Set([1, 2, 3]);
          set = new Set([...set].map(x => x * 2));
          // 返回Set结构:{2, 4, 6}
          
          let set = new Set([1, 2, 3, 4, 5]);
          set = new Set([...set].filter(x => (x % 2) == 0));
          // 返回Set结构:{2, 4}
      • 使用Set实现并集(Union)、交集(Intersect)、差集(Difference):
        • let a = new Set([1,2,3])
          let b = new Set([3,4,5])
          
          // 并集:
          let union = new Set([...a,...b])
          // union : {1, 2, 3, 4, 5}
          
          // 交集
          let intersect = new Set([...a].filter( e => b.has(e) ))
          // {3}
          
          // 差集 (a 相对于 b的差集)
          let difference = new Set([...a].filter(e => !b.has(e)))
          // {1, 2}
    • 如果想在遍历操作中,同步改变原来的 Set 结构,目前没有直接的方法,但有两种变通方法。一种是利用原 Set 结构映射出一个新的结构,然后赋值给原来的 Set 结构;另一种是利用Array.from方法。
      • 1 // 方法一
        2 let set = new Set([1, 2, 3]);
        3 set = new Set([...set].map(val => val * 2));
        4 // set的值是2, 4, 6
        5 
        6 // 方法二
        7 let set = new Set([1, 2, 3]);
        8 set = new Set(Array.from(set, val => val * 2));
        9 // set的值是2, 4, 6

3.WeakSet

WeakSet结构与Set类似,也是不重复的值的集合。但是与Set有两个区别。

 (1)WeakSet的成员只能是对象,不能是其他类型的值

const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set

 (2)WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用

也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

原文地址:https://www.cnblogs.com/codexlx/p/14345940.html