1.Set数据结构:它类似与数组,但是成员的值都是唯一的,没有重复的,Set本身是构造函数,用来生成Set数据结构的
{
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); //add(value):添加某个值,返回 Set 结构本身
for (let i of s) {
console.log(i);
};
}
// 根据这个特性,可以用于数组的去重
{
let arr = [1, 3, 2, 4, 3, 2, 4, 5, 2, 4, 5, 3, 5];
console.log([...new Set(arr)]);
}
Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
{
let set = new Set([1, 2, 45, 4, 4, 1, 2, 4, 5, 6, 8, 5, 2]);
console.log([...set]);
console.log(set.size);
let set1 = new Set(document.querySelectorAll('div'));
console.log(set1.size);
// 相当于
let set2 = new Set();
let div = document.querySelectorAll('div');
div.forEach(item => {
set2.add(item)
});
console.log(set2)
}
向 Set 加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。
Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,
它类似于精确相等运算符(===),主要的区别是NaN等于自身,而精确相等运算符认为NaN不等于自身。
{
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
console.log(set);
另外,两个对象总是不相等的
}
2.Set 实例的属性和方法
2.1Set 实例的属性
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
2.2Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
add(value) :添加某个值,返回 Set 结构本身。
delete (value) :删除某个值,返回一个布尔值,表示删除是否成功。
has(value) :返回一个布尔值,表示该值是否为Set的成员。
clear() :清除所有成员,没有返回值。
{
let set = new Set();
set.add(1).add(2).add(3).add(2);
console.log(set.size);
console.log(set.delete(2));
console.log(set.delete(6));
console.log(set);
console.log(set.has(1));
set.clear();
console.log(set)
}
2.3Array.from方法可以将 Set 结构转为数组。
{
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
console.log(array);
// 这就提供了去除数组重复成员的另一种方法。
function dedupe(array) {
return Array.from(new Set(array));
}
console.log(dedupe([1, 1, 2, 3])); // [1, 2, 3]
}
2.4遍历方法
keys() :返回键名的遍历器
values() :返回键值的遍历器
entries() :返回键值对的遍历器
forEach() :使用回调函数遍历每个成员
{
let set = new Set(['red', 'green', 'blue']);
console.log(set);
for (let item of set.keys()) {
console.log(item);
}
for (let item of set.values()) {
console.log(item);
}
for (let item of set.entries()) {
console.log(item);
}
for (let item of set) {
console.log(item);
}
}
Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
{
let set = new Set([1, 2, 3, 4, 2, 3, 21, 3, 4, 23]);
console.log(set);
set.forEach((value, key) => {
console.log('key:' + key + 'value:' + value)
})
}
2.5遍历的应用
数组的去重
{
let arr = [1, 2, 3, 2, 3, 2, 3, 2, 35, 5];
console.log([...new Set(arr)]);
}
数组的map和filter方法也可以间接用于 Set
{
let arr = [1, 2, 3, 2, 3, 2, 3, 2, 35, 5];
let setm = new Set([...new Set(arr)].map(x => {
return x * 2;
}));
console.log(setm);
let setf = new Set([...new Set(arr)].filter(x => {
return x > 2;
}));
console.log(setf)
}
实现并集,交集,差集
{
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 结构,目前没有直接的方法,但有两种变通方法。
一种是利用原 Set 结构映射出一个新的结构,然后赋值给原来的 Set 结构;
另一种是利用Array.from方法。
3.WeakSet:WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象,而不能是其他类型的值。WeakSet 不可遍历
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,
如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,
它在 WeakSet 里面的引用就会自动消失。
案例对比
const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
WeakSet {[1, 2], [3, 4]}
上面代码中,a是一个数组,它有两个成员,也都是数组。将a作为 WeakSet 构造函数的参数,a的成员会自动成为 WeakSet 的成员。
注意,是a数组的成员成为 WeakSet 的成员,而不是a数组本身。这意味着,数组的成员只能是对象。
const b = [3, 4];
const ws = new WeakSet(b);
// Uncaught TypeError: Invalid value used in weak set(…)
// 好处:WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。