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 回调参数
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 使用场景性能对比
- 内存占用,相同内存 Map 比 Object 多存储 50% 键值对,Map 占用内存小
- 插入性能,Map 更快
- 查找速度,Object 占优
- 删除操作,Map 更快
# Set 的 cdsha 及迭代、回调
c -> clear
d -> delete
s -> size // 成员数量
h -> has
a -> add // 添加指定成员
// 迭代
keys -> key 数组
values -> 与 key 相同数组
entries -> key、value 值相同的二维数组
// 回调
forEach -> 默认注入 key、value 且相同
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
Set 迭代器是 values,keys 与 values 共用一个迭代器即 values
# 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 引用,所以其占用内存无法被回收就可能引起内存泄露
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 值算法花时间学习一下还是很有必要的
扫一扫,微信中打开