Set
Set是 ES6 新增的一种集合类型,它是由一组无序且唯一(即不能重复)的项组成的,该数据结构使用了与有限集合相同的数学概念。
属性
每一个 Set 实例都有 size 属性,该属性表示该实例有多少个元素。
const set = new Set([1])
console.log(set.size);// 1
基本API
- 构建 Set 集合
使用 new 关键字创建一个 Set 实例,可以接收一个一维数组,作为初始化的数据。
const set1 = new Set();
const set2 = new Set(["key", "val"]);
console.log(set2.size)//2
const set3 = new Set([]);
console.log(set3.has(undefined))//false
- 新增值
创建实例后可以通过 add 方法添加值。可以一次添加多个值并且连续调用。
const set1 = new Set();
console.log(set1.size);//0
set1.add("key", "val");
console.log(set1.size);//1
set1.add("key1", "val1").add("key2", "key2");
console.log(set1.size);//3
- 判断值是否存在
通过 has 方法判断该值是否存在 Set 实例中。存在返回 true,不存在返回 false。
const set = new Set(["key", "val"]);
console.log(set.has("key"))//true
console.log(set.has("key1"))//false
- 删除值
通过 delete 方法删除值。传入要删除的值。要删除的值在实例中则删除并返回 true,否则返回 false。
const set = new Set(["key", "val"]);
console.log(set.delete("key"))//true
console.log(set.size);
console.log(set.delete("key1"))//false
- 清空 Set 集合
通过 clear 方法清空 Set 实例的值。
const set = new Set(["key", "val"]);
console.log(set.size);//2
set.clear();
console.log(set.size);//0
- SameValueZero 规则
Set 可以存储任何 JS 类型。 Set 使用 SameValueZero(类似于严格对象相等)来确定键值是否已存在。即便更改了对象属性也依然能够判断。
const obj = {}
const set = new Set([obj, "val"]);
console.log(set.has(obj), set.size);//true 2
obj.name = "123";
set.add(obj);
console.log(set.has(obj), set.size);//true 2
迭代
Set 能够按照键值对的插入顺序迭代输出。并且 Set 实例提供了一个迭代器以便能够通过特特定方法按顺序迭代。
- entries
调用本方法会返回一个迭代器。迭代结果是一个二维数组,元素值都为每一项的值
const set = new Set([1, 2, 3, 4]);
for (let item of set.entries()) {
console.log(item);
}
- values | keys
这两个方法是一样的,调用方法会返回一个按照插入顺序的值的迭代器。并且是默认迭代器。所以可以使用扩展操作符,使用 for of 迭代 Map 实例时可以省略显示调用 values();
const set = new Set([1, 2, 3, 4]);
for (let item of set.values()) {
console.log(item);
}
console.log("-----------");
for (let item of set) {
console.log(item);
}
console.log("-----------");
console.log([...set]);
- 不使用迭代器
当然也可以不使用迭代器而是用回调的方式迭代,示例如下。回调函数的第一个参数是值,第二个参数是键。这里键和值是一样的。
const set = new Set([1, 2]);
set.forEach((val, key) => {
console.log(key + ":" + val);
})
需要注意的是如果在迭代过程中修改给了每次迭代的结果,并不会影响映射关系,如下例
const set = new Set([1, 2]);
for (let item of set.values()) {
item = 3;
console.log(item);
}
console.log(set);
由输出结果可知在遍历的过程中使 item 的值为 3,因此输出两次 3,并没有改变 set 实例的值。
weakSet
weakSet 也是 ES6 新增的一种集合类型,它有如下特点:
- 键只能是 Object 类型或继承自 Object 类型,否则会抛出错误。
- weakSet 实例对该键 Object 是弱引用(后边会详细讲),不会影响 JS 的垃圾回收。
- weakSet 的基本 API 比 Set 的少了 clear(清空)方法,因为特点2,所以没有必要再持有该方法。
- weakSet 没有提供迭代其实例键值对的迭代器。因为特点2,所以 weakMap 实例中的键值对随时随地都有可能被销毁。
- weakSet 实例没有 size 属性。
- weakMap 也可以像构建 Map 那样构建,也有 add、has、delete方法。
什么是弱引用
JS 有一种垃圾回收策略叫做引用计数,通俗理解就是声明一个对象后,JS 就会使用一个变量用来保存该对象被使用的次数,如果被使用次数为 0 ,那么 JS 就会销毁该对象,释放内存。
给个例子
const obj1 = { name: 1 }, obj2 = { name: 2 };
const set = new weakSet([obj1, obj2]);
这里弱引用的意思是当我实例化了一个 weakSet 集合 Set,并且使用 obj1 和 obj2 作为值存入 Set 中,那么此时 set 使用了 obj1 和 obj2,但是由于 set 是 weakSet 实例,所以 obj1 和 obj2 的被使用次数并不会加 1,那么一旦 obj1 和 obj2 又没有在别的地方被使用,JS 就会回收 obj1 和 obj2,set 就失去了值。
因此 weakSet 实例没有提供迭代器,因为也许你刚迭代完,该对象就被回收了,内存都被释放了,那么此时的迭代就没有了意义。也正因此 weakSet 舍弃了 clear API。并且即使能够访问 weakSet 实例也无法看到其存储的键值对。
还需要注意 weakSet 的好兄弟 Set 就不是这样,Set 实例对于键的应用是强引用,只要 Set 实例没被回收,那么其存储键值对就会一直存在,不会被 JS 私自回收。
我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。