es6 Set和WeakSet

Js大部分历史时期都只存在一种集合类型,也就是数组类型。数组在 JS 中的使用正如其余语言的数组同样,但缺乏更多类型的集合致使数组也常常被看成队列与栈来使用。数组只使用了数值型的索引,而若是非数值型的索引是必要的,开发者便会使用非数组的对象。这种技巧引出了非数组对象的定制实现,即 Set 与 Map 。es6

Set:

Set概述

Set对象是值的集合,你能够按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是惟一的。编程

 Set结构相似于数组,可是没有重复结构
 Set会自动移除重复的值,所以能够用来过滤数组中的重复结构
 Set内的对象是强引用

Set的构造:

a)    let set = new Set([1, 2, 3, 4]);

Set 构造器实际上能够接收任意可迭代对象做为参数。能使用数组是由于它们默认就是可迭代的,Set与Map也是同样,Set构造器会使用迭代器来提取参数中的值数组

b)    let set = new Set();

    set.add(1);
    set.add(2);
    set.add(2);
    //若是add对相同的值进行了屡次调用,那么那么在第一次以后的调用实际上会被忽略
    set.add(3);
    set.add('3');

Set 不会使用强制类型转换来判断值是否重复。这意味着 Set 能够同时包含数值 3 与 字符串 "3" ,将它们都做为相对独立的项.
Set判断是否重复使用了Object.is() 方法,惟一的例外是 +0 与 -0 在 Set 中被判断为是相等的数据结构

c) 还能够向Set添加多个值相同的对象,他们不会被合并为同一项。函数

let set = new Set();
let key1 = {};
let key2 = {};
set.add(key1);
set.add(key2);

Set的属性及方法:

一、属性

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

二、方法

Set的方法分为两类:操做方法 和 遍历方法this

2.一、操做方法:

•add(value):添加某个值,返回 Set 结构自己。
  由于返回set自己,因此能够写成:
  set.add(1).add(2).add(3)

•delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
 set.delete(2) ; // true

•has(value):返回一个布尔值,表示该值是否为Set的成员。
 set.has(2) ; // false

•clear():清除全部成员,没有返回值。

2.二、遍历方法:

forEach():使用回调函数遍历每一个成员

es5给数组添加了forEach()方法,使得更容易处理数组中的每一项,没有返回值
对于数组来讲forEach的三个参数:
arr[].forEach(function(value,index,array){//do})
value数组中的当前项, index当前项的索引, array原始数组es5

可是对于Set来讲:prototype

let set2 = new Set([{'a':1}, {'b':2}]);
    set2.forEach(function(value, key, ownerSet) {
      console.log(ownerSet === set2);
      console.log(value === key);
    });

key 与 value 老是相同的,同时 ownerSet 也始终等于 set 。此代码输出:
true
true
true
true

若是想在回调函数中使用当前的this,还能够在forEach中传入this做为第二个参数code

let set = new Set([1, 2]);
let processor = {
    output(value) {
    console.log(value);
  },
  process(dataSet) {
    dataSet.forEach(function(value) {
      this.output(value);
    }, this);
  }
};
processor.process(set);

本例中,在processor.process方法中的set调用了forEach方法,并传递了this做为第二个参数,这样便能正确的调用到this.output()方法
或者也可使用箭头函数来达到相同的效果,无需传入this,只需将上边的process改写成:对象

process(dataSet) {
  dataSet.forEach((value) => this.output(value));
}
keys()、values()和entries()

keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器

keys方法、values方法、entries方法返回的都是遍历器对象,因为Set结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys方法和values方法的行为彻底一致。

let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

上面代码中,entries方法返回的遍历器,同时包括键名和键值,因此每次输出一个数组,它的两个成员彻底相等。

Set 结构的实例默承认遍历,它的默认遍历器生成函数就是它的values方法。
Set.prototype[Symbol.iterator] === Set.prototype.values
// true
这就意味着,能够省略values方法,直接用for…of循环遍历Set

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue

Set经常使用场景

Set最经典的应用就是数组排重:

let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array);

Set与其余数据结构的互相转换

一、 Set与数组的转换

1.一、 Set转数组

使用扩展运算符能够很简单的将Set转成数组

let set = new Set([1, 2, 3, 3, 3, 4, 5]),
let array = [...set];
console.log(array); // [1,2,3,4,5]

该示例很好的说明了Set的一个重要的功能,数组排重,固然也很好的展现了,如何从Set转成数组的过程。
注意,这种转变是生成了一个新的数组对象原来的Set依然存在。

1.二、 数组转Set

如最初的构造示例:

let set = new Set([1,4,5,6,7]);

WeakSet:

因为 Set 类型存储对象引用的方式,它也能够被称为 Strong Set 。对象存储在 Set 的一个实例中时,实际上至关于把对象存储在变量中。只要对于 Set 实例的引用仍然存在,所存储的对象就没法被垃圾回收机制回收,从而没法释放内存。

当 JS 代码在网页中运行,同时你想保持与 DOM 元素的联系,在该元素可能被其余脚本移除的状况下,你应当不但愿本身的代码保留对该 DOM 元素的最后一个引用(这种状况被称为内存泄漏)
为了缓解这个问题, ES6 也包含了 Weak Set ,该类型只容许存储对象弱引用,而不能存储基本类型的值。对象的弱引用在它本身成为该对象的惟一引用时,不会阻止垃圾回收。
WeakSet 里面的引用,都不计入垃圾回收机制,因此就不存在这个问题。所以,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失

WeakSet的构造:

Weak Set 使用 WeakSet 构造器来建立:

let set = new WeakSet(),
key = {};
// 将对象加入 set
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false

WeakSet的属性和方法:

基于WeakSet的弱引用特性,且里边的对象有可能随时消失的特性,es6规定WeakSet不可遍历,且没有size属性,WeakSet只有如下三个方法:
WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

WeakSet的特性

  1. 对于 WeakSet 的实例,若调用add()方法时传入了非对象的参数,就会抛出错误(has()或delete()则会在传入了非对象的参数时返回false);
  2. Weak Set 不可迭代,所以不能被用在 for-of 循环中;
  3. Weak Set 没法暴露出任何迭代器; (例如 keys()与values() 方法,所以没有任何编程手段可用于判断 Weak Set 的内容);
  4. Weak Set 没有 forEach() 方法;
  5. Weak Set 没有 size 属性。

WeakSet之因此不可遍历是因为 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行先后极可能成员个数是不同的,而垃圾回收机制什么时候运行是不可预测的,所以 ES6 规定 WeakSet 不可遍历。WeakSet经常使用场景Weak Set 看起来功能有限,而这对于正确管理内存而言是必要的。通常来讲,若只想追踪对象的引用,应当使用 Weak Set 而不是正规 Set

相关文章
相关标签/搜索