Skip to main content

Map|Set|WeakMap|WeakSet

Map

Map 是一个带键(键是唯一的)的数据项的可迭代、有序集合(它会记住键的插入顺序)。使用Map构造函数可以传入一个带有键值对的数组(或其它可迭代对象)来进行初始化。

info

Map与Object的比较

Map 使用 SameValueZero 算法 来比较键是否相等。它和严格等于 === 差不多,但区别是 NaN 被看成是等于 NaN。所以 NaN 也可以被用作键。这个算法不能被改变或者自定义。

Map的方法和属性

  • new Map([iterable]) —— 创建 map,入参(可选)为一个元素是键值对的数组或其他可迭代对象(例如,包含两个元素的数组,如 [[ 1, 'one' ],[ 2, 'two' ]])每个键值对都被添加到新的 Map 中。
  • map.set(key, value) —— 根据键存储值。每一次 map.set 调用都会返回 map 本身,所以我们可以进行“链式”调用:map.set('1', 'str1').set(1, 'num1').set(true, 'bool1');
  • map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined
  • map.has(key) —— 如果 key 存在则返回 true,否则返回 false。
  • map.delete(key) —— 删除指定键的值,如果在调用时 key 存在,则返回 true,否则返回 false。
  • map.clear() —— 清空 map。
  • map.size —— 返回当前元素个数。
  • map.keys() —— 遍历并返回一个包含所有键的可迭代对象。
  • map.values() —— 遍历并返回一个包含所有值的可迭代对象。
  • map.entries() —— 遍历并返回一个包含所有实体 [key, value] 的可迭代对象,map应用for..of时 在默认情况下使用的就是这个。
  • map.forEach() —— 迭代map

Set

Set 是一个特殊的类型集合 —— “值的集合”(没有键),它的每一个值(无论是原始值还是对象引用)只能出现一次。可以按照插入顺序迭代集合中的元素。

Set的方法和属性

  • new Set([iterable]) —— 如果传入一个可迭代对象(如数组[1, 2, 3, 4, 5]),它的所有元素将不重复地被添加到新的 Set 中。如果不指定此参数或其值为 null,则新的 Set 为空。
  • set.add(value) —— 添加一个值,返回 set 本身
  • set.delete(value) —— 删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false。
  • set.has(value) —— 如果 value 在 set 中,返回 true,否则返回 false。
  • set.clear() —— 清空 set。
  • set.size —— 返回元素个数。
  • set.keys() —— 遍历并返回一个包含所有值的可迭代对象。
  • set.values() —— 与 set.keys() 作用相同,这是为了兼容 Map。
  • set.entries() —— 遍历并返回一个包含所有的实体 [value, value] 的可迭代对象,它的存在也是为了兼容 Map。
  • set.forEach((value,value,set)=>{}) —— 迭代set(注意:回调函数的前两个入参是同一个值,也是为了兼容 Map)

WeakMap

info

通常,当对象、数组之类的数据结构在内存中时,它们的子元素,如对象的属性、数组的元素都被认为是可达的。例如:

  • 如果把一个对象放入到数组中,那么只要这个数组存在,那么这个对象也就存在,即使没有其他对该对象的引用。

  • 如果我们使用对象作为常规 Map 的键,那么当 Map 存在时,该对象也将存在。它会占用内存,并且不会被(垃圾回收机制)回收。

WeakMap的方法

tip

WeakMap 的键必须是对象,不能是原始值。

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok"); // 正常工作(以对象作为键)

// 不能使用字符串作为键
weakMap.set("test", "Whoops"); // TypeError: Invalid value used as weak map key,因为 "test" 不是一个对象
  • WeakMap 只有以下的方法:

    • weakMap.get(key)
    • weakMap.set(key, value)
    • weakMap.delete(key)
    • weakMap.has(key)
  • WeakMap 不支持迭代以及 keys(),values() 和 entries() 方法。所以没有办法获取 WeakMap 的所有键或值。

WeakMap与垃圾回收

  • WeakMap 不会阻止垃圾回收机制对作为键的对象(key object)的回收。如果在 WeakMap 中使用一个对象作为键,并且没有其他对这个对象的引用,则该对象将会被从内存中自动清除。
info

如果一个对象丢失了其它所有引用,那么它就会被垃圾回收机制自动回收。但是不能准确知道 何时会被回收。这些都是由 JavaScript 引擎决定的。JavaScript 引擎可能会选择立即执行内存清理,如果现在正在发生很多删除操作,那么 JavaScript 引擎可能就会选择等一等,稍后再进行内存清理。

WeakMap的应用场景

  • WeakMap 的主要应用场景是 额外数据的存储。

使用WeakMap存储额外的数据

  • WeakMap 的另一个应用场景是缓存,存储(“缓存”)函数的结果,以便将来对同一个对象的调用可以重用这个结果。

使用WeakMap缓存结果

WeakSet

  • 只能向 WeakSet 添加对象(而不能是原始值)。

  • 对象只有在其它某个(些)地方能被访问的时候,才能留在 WeakSet 中。

  • WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代