time: 2021.3.11
author: heyunjiang
在阅读 vue3 源码时,看到 track 收集依赖时,广泛使用了 Map, weakMap 数据结构,之前自己是熟悉使用 array, object 来操作。
现在总结一下 set, map 的基础语法,对比 array, object 来看有什么优点
Set, Map 作为宿主环境提供的全局对象,是作为构造函数使用 const s = new Set()
构造函数接受数组或具有 iterable 接口的其他数据结构,并且数组的每一项要求是对象
实例属性和方法
- set.size: 返回内部成员总数
- set.add()
- set.delete()
- set.has()
- set.clear()
- set.keys()
- set.values()
- set.entries()
- set.forEach()
特点
- keys 和 values 返回结果一致,因为 set 没有键名,只有键值。entries 的2个参数也是一样的
- set 的遍历顺序就是插入顺序,也就是说通过4个原型遍历 set 结构,是按原顺序的,这点和 Object.prototype.forEach 的遍历不确定性是不同的
- 也可以通过 ... 和 for of 遍历
和 Set 不同点
- WeakSet 只支持对象
- WeakSet 添加的对象,属于对对象的弱引用,垃圾回收器不会考虑它的影响
- WeakSet 不能遍历,也没有 size 属性,因为内部弱引用的对象随时可能被垃圾回收器回收掉,无法保证遍历时对象是否存在,可能遍历之后对象就消失了
WeakSet 支持的方法
- weakset.add()
- weakset.delete()
- weakset.has()
Object 要求只能以 string 作为 key,而 Map 对象是支持任意值作为 key,包括非 string 的所有类型
Map 构造函数要求是数组或具有 iterable 接口的其他数据结构,并且数组的每一项要求是 length = 2 的数组,分别代表 key, value
实例属性和方法
- map.size:返回内部成员总数
- map.set(key, value): 这点和 set.add() 不同
- map.get(key): set 没有
- map.has(key)
- map.delete(key)
- map.clear(): 同 set 一样,清除所有成员
- map.keys()
- map.values()
- map.entries()
- map.forEach()
注意事项
- 只有对同一个对象的引用,也就是内存地址一样,map 才会视为同一个键
- 同 set 一样,Map 的遍历顺序就是插入顺序
和 Map 不同点
- WeakMap 只接受对象作为 key
- WeakMap 添加的对象,属于对对象的弱引用,垃圾回收器不会考虑它的影响
- WeakMap 不能遍历,也没有 size 属性,因为内部弱引用的对象随时可能被垃圾回收器回收掉,无法保证遍历时对象是否存在,可能遍历之后对象就消失了
这些不同点和 WeakSet 一样
set, map 在日常项目中就会用到,因为它能带给我们 array, object 不能提供的能力
但是 weak 的大特性是其对内部对象的弱应用,有哪些使用场景呢?
文档说的是对 dom 元素的引用,那我再看完 vue3 track 收集依赖再来回答这个问题
- 值的唯一:set 内部值必须唯一。注意 object 时存储的是引用地址
- 内部支持方法不一样,通常 set 用于数组去重,无法替代 array
- 键的类型:map 的键可以是 object 的 string, symbol,也可以是 函数、对象或其他任意基本类型
- 键的顺序:map 的键保存了顺序,所以在使用 for of 或 forEach 遍历时可以保证顺序,而 object 则不能保证顺序
- 键的个数:map 可以通过 size 熟悉直接访问到,而 object 则需要 Object.keys 获取然后读取数组属性
- 迭代:map 可以使用 for of 或 forEach 迭代,而 object 则需要使用特有的 for in 循环遍历
- 优化:在频繁增删键值对的场景,map 内部做了优化
那是否可以直接使用 map 替代 object 了?
vue3 for 循环还是支持 object