
长久以来,数组一直是JS中唯一的集合类型。由于数组使用的是数值型索引,因此如果需要使用非数值索引就会用非数组对象创建所需的数据结构,这就是Set和Map的早期实现
但通过Object.create(null)这种形式模拟的集合有很多问题,比如所有对象的属性名必须是字符串类型,必须确保每个键名都是字符串类型且在对象中是唯一的。
而且判断存在时,若值为1可能会混淆。
Set集合
Set类型是一种有序列表,允许你存储任何类型的唯一值,通过Set集合可以快速的访问其中的数据
传入完全相同的值,后者会被忽略
注意Set认为+0与-0、NaN与NaN是相同的
方法
add // 添加
clear // 移除全部
delete // 移除某个
has // 查看是否存在某个元素
forEach // 为每个元素调用一次callBackFun(value,key,ownerSet)
三种生成迭代器的方法
entries()
keys()
values()
注意Set集合本没有键名,但为了与其他集合保持键值对的形式,所以让Set集合的每个元素也按键值对的形式存储,但键和值完全一样(包括类型)
let set = new Set([1, 2]);
set.forEach((value, key, ownerSet) => {
console.log(key + ": " + value);
console.log(typeof key);
console.log(key === value);
});
forEach的第二个参数可以传入this,或者第一个参数是箭头函数形式绑定this
转换
let set = new Set([1,2,3,3,3,4,5])// 数组转换为Set,会自动去重
[...set]// Set转换为数组 [1,2,3,4,5]
WeakSet
我们都知道,为了不造成内存泄漏,最好及时的将不再使用的变量设为null,从而确保其内存可以在适当的时候被回收
将对象存储在Set的实例与存储在变量中完全一样,只要Set实例中的引用存在,垃圾回收机制就不能释放该对象的内存空间
let set = new Set();
key = {};
set.add(key);
console.log(set.size);
key = null;
console.log(set.size); // 1
key = [...set][0];
console.log(key); // {}
为了解决内存泄漏问题,WeakSet集合诞生了,顾名思义即弱引用Set集合。
WeakSet集合只存储对象的弱引用,并且不可以存储原始值;集合中的弱引用如果是对象唯一的引用,则会被回收并释放相应的内存
key1 = {};
key2 = {}
let set = new WeakSet([key1,key2]);
console.log(set.has(key1));// true
key1 = null;// 移除对象key1的最后一个强引用(WeakSet中的引用也会被自动移除)
方法
add
has
delete
区别
- 在WeakSet实例中,如果向add()传入非对象参数会导致程序报错,向has()和delete()传入非对象参数会返回false
- WeakSet集合不暴露任何迭代器,不可迭代
- 不支持forEach方法和size属性
Map
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
方法
new Map([['name','yqx']]) // 初始化
set // 添加
get // 获取
其他与Set集合差不多
比较
| Map | Object | |
|---|---|---|
| 意外的键 | 默认不包含任何键 | 有一个原型,有可能和原型链上的键名有冲突,虽然可以用Object.create(null)创建一个没有原型的对象,但这种用法并不常见 |
| 键的类型 | 任意值 | 必须是String或Symbol |
| 键的顺序 | 有序 | 无序 |
| Size | 可以通过size属性获取键值对个数 | 只能手动计算 |
| 迭代 | 可以 | 默认不可以,需要修改Symbol.iterator属性才可以 |
| 性能 | 在频繁增删键值对的场景下表现更好 | 未作出优化 |
WeakMap
与WeakSet大部分设计理念一至
方法多列一个get方法用于获取某个元素
补充一下,VUE3中的响应式实现原理有使用到这个新特性