Set、WeakSet、Map、WeakMap的区别

1,538 阅读4分钟

先讲每个构造函数是干什么的,最后总结它们的区别。

Set

集合,类似于数组,集合中的值唯一,Set本身是一个构造函数,可用new创建对象,Set函数可接受一个数组作为参数用来初始化集合。

利用Set去除数组重复成员的方法

[... new Set(array)]
// 返回一个新数组,该数组来自一个Set集合
Array.from(new Set(array));

利用Set去除字符串里的重复字符:

[... new Set('abbaa')].join('')

判断Set中加入的值是否唯一使用的是和“===”类似的运算符,只是Set认为NaN是等于NaN的,而“===”认为NaN !== NaN

set有一些方法:

  • Set.prototype.constructor,构造函数,默认是Set函数;
  • Set.prototype.size,Set实例的成员总数;
  • add(value)
  • delete(value)
  • has(value)
  • clear(),清除所有成员

WeakSet

和Set类似,里面的元素都唯一,但成员只能是对象,不能是其他类型的值(即每个成员用typeof 都是object,每个成员都是引用)。

WeakSet是弱引用,即它里面保存的对象,只要不再被外部变量引用,则就就会被垃圾回收机制回收,所以,WeakSet只适合保存一些临时的对象。

WeakSet无法被遍历,因为它里面有多少个成员,取决于垃圾回收机制有没有运行,运行前后成员个数不一样。也就说,可能遍历的时候某个成员还在,下一秒就被回收消失了,所以直接不允许WeakSet遍历。

创建WeakSet实例时,也可以传入一个数组或类数组对象。当然,传入的数组中的元素必须是引用类型(对象、数组)。 实例方法:

  • add(val)
  • delete(val)
  • has(val)
  • 无size属性
  • 无forEach

Map

键值对的集合,键可以是任意类型,值也可以是任意类型。

通常用的实例方法:

Map.prototype.set(key, val);	// 添加成员
Map.prototype.get(key);

Map实例创建的时候也可以接受数组,但数组的元素必须是一个个表示键值对的数组。实际上任何实现了Iterator接口并每个成员都是一个双元素数组的数据结构,都可以当作是Map的参数。

如果对同一键赋值,后面的值将覆盖前面的值。

【小心】只有对同一个对象的引用,Map结构才将它视为同一个键。如下,看上去是同一个键,但他们的内存地址是不一样的。同样值的两个实例,比如const k1 = ['a'],const k2 = ['a'],他们会被视为两个不同的键,因为他们的地址不一样。

const map = new Map();
map.set(['a'], 555);
map.get(['a']);		// undefined

由上可知,Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。

如果Map的键是一个简单类型的值,则它们只要严格相等,Map会视它为同一个键。

【注】Map视NaN为同一个键,虽然NaN !== NaN

一些实例方法:

  • size();
  • set(key, val);
  • get(key);
  • has(key);
  • delete(key);
  • clear(key);

WeakMap

和Map的区别:

  1. 只接受对象作为键名(null除外),Symbol不是对象,也不能作为键名。
  2. WeakMap的键所指向的对象,不计入垃圾回收机制(即垃圾回收机制不把WeakMap中元素的键名所引用的对象考虑在内,只有该对象的其他引用都被清除后,垃圾回收机制就会将该对象回收)。所以WeakMap中的成员随时都有可能消失。典型应用场景如下:
    const wp = new WeakMap();
    const element = document.getElementById('example');
    wm.set(element, 'some information');
    wm.get(element); 	// 'some information'
    
    wm实例中有键值对element => 'some information',也就是这个键值对引用着element对象,此时一旦该对象的其他引用都被取消,比如element = null,那么,该对象就会随时被垃圾回收机制回收,回收后,这个键值对也会被删除,它并没有顾及这个键值对还引用着这个DOM元素对象。 WeakMap最大的特定就是,它的成员在将来可能会自动消失。

最典型的用途就是如上的例子,比如每点一次鼠标,就为某个DOM元素更新一个描述,一旦该DOM元素被回收,那么WeakMap中的描述键值对也会消失。

区别

Set、WeakSet都是元素的集合,而Map和WeakMap是键值对的集合。

Set和WeakSet的区别

  1. 里面的元素都唯一,Set的元素可以是任何值,而WeakSet的元素只能是对象。
  2. 对于基本类型的值,只要“===”为真,则这两个值相等(无法加入Set中)。对于引用类型(Set和WeakSet中),只有地址相同,它们才不唯一,而值相同的两个不同对象,它们是不同的。
  3. NaN被视为同一个值。
  4. WeakSet中的元素是弱引用,即随时会消失(被回收)。

Map和WeakMap的区别

  1. Map的键和值都可以是任意类型,而WeakMap的键只能是对象。
  2. Map和WeakMap的键必须唯一,判断方式是“===”和是否地址相同。
  3. Map视NaN为同一个键。
    1. WeakMap中的键值对的键是弱引用,WeakMap中的成员随时会消失。