关于 Map 与 Set 聊点别的

ES6 新增了 Map 映射,Set 集合

从 API 应用角度来看,相当简单,没必要写点什么

的确,所以聊点别的

顺带介绍下 API

# Map 的 cdshg 及迭代、回调

c -> clear  // 清除所有成员
d -> delete // 删除指定成员
s -> size、set // 成员数量,添加指定成员
h -> has // 判断是否有指定成员
g -> get // 获取指定成员

// 迭代
keys -> key 数组
values -> value 数组
entries -> [[key, value]] 二维数组
// 回调
forEach -> 默认注入 key、value 回调参数
1
2
3
4
5
6
7
8
9
10
11
12

# 映射 Map 与 WeakMap

WeakMap 是 Map 的同胞兄弟类型,但 API 是 Map 子集,因为只有部分

  • Map 以任意数组类型作为 key,WeakMap 只能以 Object 或继承 Object 类型作为 key
  • Map 有 clear 方法及迭代、回调方法,WeakMap 没有,当然 WeakMap 上也同样没有部署 [Symbol.iterator] 迭代器接口

# Map 与 Object 使用场景性能对比

  1. 内存占用,相同内存 Map 比 Object 多存储 50% 键值对,Map 占用内存小
  2. 插入性能,Map 更快
  3. 查找速度,Object 占优
  4. 删除操作,Map 更快

# Set 的 cdsha 及迭代、回调

c -> clear
d -> delete
s -> size // 成员数量
h -> has
a -> add // 添加指定成员

// 迭代
keys -> key 数组
values -> 与 key 相同数组
entries -> key、value 值相同的二维数组
// 回调
forEach -> 默认注入 key、value 且相同
1
2
3
4
5
6
7
8
9
10
11
12

# 集合 Set 与 WeakSet

此处省略,参照映射 Map 与 WeakMap

# 集合 Set 与映射 Map 对比

  • 相同的迭代、回调方法
  • Set 没有 get 方法,为什么没有?集合更偏重交集、全集、差集等操作,这些有 has 就够了,get 获取成员完全没必要
  • Set 添加方法是 add(Map->set,Set->add,Array->push)
  • Map 默认迭代器是 entries, Set 默认迭代器是 values,由于 keys 与 values 返回相同的值,所以 keys,values 共用一个迭代器,即 keys === values 结果为 true

# 查看映射 Map 与集合 Set 迭代器

Map 迭代器是 entries

Map 迭代器

Set 迭代器是 values,keys 与 values 共用一个迭代器即 values Set 迭代器

# Map、Set 幂等操作函数

意思:幂等函数或幂等方法是指可以使用相同参数重复执行,并能获得相同结果的函数

显然 Map 幂等操作函数:set、has、get

Set 幂等操作函数:add、has

数组呢?显然 push 操作不是幂等的

# 作为 key 的算法

使用 SameValueZero (opens new window) 比较算法

在严格相等比较基础上,NaN 与 NaN 比较结果为 true

区别与 Object.is 的 SameValue (opens new window) 算法

比较 NaN 与 NaN 结果为 true

比较 +0 与 -0 结果为 true

严格相等比较(===),即 IsStrictlyEqual (opens new window) 算法

比较 NaN 与 NaN 为 false

+0 与 -0 为 true

宽松相等比较(==),即 IsLooselyEqual (opens new window) 算法

隐式类型转换的比较

比较有技术含量的算法细节 (opens new window)

# 关于弱的理解

WeakMap、WeakSet 中的 Weak 表示弱的意思

意思是他们的键不属于正式的引用,即不会阻止 Javascript 垃圾回收

另外一层意思,表示 API 相对其兄弟类型少了点,没有 clear 与迭代、回调这些

# WeakMap、WeakSet 使用场景

当 WeakMap 的 key 除了自身不在其他地方引用时,会默认被 GC

移除的 DOM 节点其引用应被 GC

// WeakMap 实现,WeakSet 实现一样
const vm = new WeakMap()
const eleBtn = document.querySelector('button')

// 绑定一些数据
vm.set(eleBtn, {id: 100})

eleBtn.parentElement.removeChild(eleBtn)

// 当 eleBtn 节点被移除时,其占用内存被释放,因为 eleBtn 没有在其它地方被引用,除了 WeakMap 本身

// 若使用 Map 实现
const m = new Map()
// code ...,eleBtn 就算被移除,但其引用被 Map 引用,所以其占用内存无法被回收就可能引起内存泄露
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 小结

  • 很多人拿 Map 与 Object 对比,意思是 Map 支持任意数据类型作为 key, Object 只能作用字符串、数字、符号(Symbol); 还有很多人拿 Set 与 Array 对比,Set 天然对成员去重,所以添加操作是幂等的,Array 不去重所以添加操作不是幂等的; 其实我想说以上真没啥可对比的,不同的 API 自身有自己的特色,何必强行对照

  • Map 与 Set API 上有许多相似之处; 比如相同的迭代、forEach 回调方法,clear、delete、has、size 属性; 只是添加成员,Map -> set,Set -> add; 另外值得注意的是 Set 没有类似 Map get 获取成员方法,因为偏重点不同

  • 映射 Map、集合 Set 都有自己的Weak版本,只能以 Object 为 key,不支持迭代、forEach 回调及 clear 方法,若 key 除了自身在其他地方无引用,GC 默认回收

  • Map 迭代器是 entries;Set 迭代器是 values,keys 复用 values 函数,顺带说下 Array 迭代器与 Set 相同也是 values

  • 幂等操作,key 值算法了解下,开发中不必刻意在意,但 key 值算法花时间学习一下还是很有必要的

    扫一扫,微信中打开

    微信二维码