JavaScript易混淆知识点——Set、Map


说明:易混淆知识点是指不同于基本数据结构的知识点。

Set

Set在JS中是表示集合的,很好记。

元素唯一性

Set具有集合的特征:元素唯一性。
放在JS中,它实际上是键的唯一性,因为每个元素都是键值对,只不过键完全等于值。
唯一性的含义:类别、值、地址完全相等。和全等符号===不同之处只有一个:NaN是唯一的。也就是说:

let a = NaN, b = NaN;
a === b // false
let set = new Set();
set.add(a);
set.add(b);
console.log(set); // 只有一个NaN,保持唯一性了

此外,对于引用类型(非原始类型,如ArrayObject),即使类别、值相等,它们也不一定是一样的,因为引用可以理解为指针,它们指向的空间存放的数据虽然完全相同,但是它们的空间地址不同,不能叫一样。用Java的概念去理解的话,就是对象的唯一性id不一样。

let a = {};
let b = {};
let c = a;
let set = new Set();
set.add(a);
set.has(b); // false
set.has(c); // true,因为地址相同,即对象id相同,即是同一个对象!
set.add(b); // 此时set中含有两个空对象

此外,Set在加入元素时,不会改变它的类型,否则就不能进行唯一性判断了。

元素遍历

由于JS的对象的复杂性,并不是所有元素都会在遍历方法中被遍历到。
keys()values()方法返回迭代器,行为基本完全一样,因为Set的键和值是相等的。而entries()确实返回键值对的迭代器,只不过键和值相等,所以基本上用不上它。
Set可以直接用for ... = of ... 遍历,它执行的是values()方法。
Set可以用forEach遍历。
Set的遍历顺序等于元素加入顺序。当加入时判断唯一性失败,并不执行覆盖操作,也就是说以第一次添加的顺序为准。
Set可以用扩展运算符...解构,因为它实际上是执行for ... of ...
Set解构为数组后,可以模拟交集、并集和差集的操作,可以使用Array的方法,如filter()

特殊方法

集合操作union(), difference(), intersection(), symmetricDifference(), isSubsetOf(), isSupersetOf(), isDisjointOf()

WeakSet

weak部分是它和Set的区别所在。它的键只能是引用类型或Symbol类型,不能是null,而且都是弱引用,可以被垃圾回收。因此,WeakSet不可遍历,也没有size属性。
weak并不是指弱唯一性!
Symbol不是引用类型!但是它却很像!
需要注意的是,如果用一个狭义的一维数组构造一个WeakMap对象,会失败,因为它遍历所得的元素都是基本数据类型,不允许加入WeakMap。但如果是一个狭义的二维数组,或者一个元素都是引用类型的数组,则可以用于构造WeakMap
它的应用场景是可以存储DOM结点,不用担心内存泄露

Map

对比

它和Set的区别是键值可以不相等,然而键仍然是唯一的。判断唯一性时,和Set一样:只要严格相等,则认为是相等的;例外就是NaN只能在键中出现一次。

它和Object的区别是键可以是除了字符串意外的任何其他类型,而Object的键只能是字符串或Symbol
细节上的区别:

  1. Map可以有一个null键。
  2. Object内部属性的顺序和插入顺序无关。
  3. Object没有size或length属性,但可以通过遍历方法如keys()来获得内部属性的个数。

构造

Map接收遍历的结果为含有两个元素的数组的类型作为参数,进行新Map的构造。例如,new Set(['a': 1, 'b':2])可以用于构造Map,一个Object可以用来构造Map,一个二维数组可以用于构造Map。当插入时出现了唯一性冲突,则新插入的值会覆盖该键原本的值。这个行为和Java的一样。
读取不存在的键,返回undefined
set()方法返回原Map对象,因此可以链式调用。

遍历

Map的默认遍历方法是entries()

WeakMap

它的特性非常类似于WeakSetnull以及其他非引用和Symbol类型不能作为键,对于键都是弱引用。

WeakRef(ES2021)

直接创建对象的弱引用。

let origin = {};
let weak_origin_ref = new WeakRef(origin);

let check = weak_origin_ref.deref(); // 如果已经被回收,返回undefined
if (check) {
	// 如果没有被回收,deref()返回原始对象
}

WeakRef可以用作缓存,如果没有被回收,就直接取值,否则重新加载。
一旦使用WeakRef()创建了原始对象的弱引用,那么在本轮事件循环,原始对象肯定不会被清除,只会在后面的事件循环才会被清除。

FinalizationRegistry(ES2021)

用于注册一个对象被销毁的事件监听。每个被注册的对象只会形成弱引用。
语法:let a = new FinalizationRegistry(回调函数); a.register(一个对象, 回调函数的参数);

Object类型的多个遍历方法区分

  • for ... in ... :遍历自身的和继承的可枚举属性名,不含Symbol类型的属性名。
  • Object.keys(obj):遍历自身的可枚举属性名,不含Symbol类型,不含继承的。
  • Object.getOwnPropertyNames(obj):遍历自身的所有属性名,Symbol类型除外,包含不可枚举类型,不包含继承属性。
  • Object.getOwnPropertySymbols(obj):只返回自身的Symbol类型属性名。
  • Reflect.ownKeys(obj):返回自身的所有属性名,包含Symbol类型,和不可枚举类型,不包含继承。

遍历属性的顺序不是插入属性的顺序!而是先数值类型(实际上是只包含数字的字符串),然后字符串类型的属性名,然后是Symbol类型的属性名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值