Map/Set 和 WeakMap/WeakSet 的区别?使用场景是什么?
对比表
| 特性 | Map | WeakMap | Set | WeakSet |
|---|---|---|---|---|
| 键类型 | 任意 | 仅对象 | — | — |
| 值类型 | 任意 | 任意 | — | 仅对象 |
| 可遍历 | ✅ | ❌ | ✅ | ❌ |
| 强引用 | ✅ | ❌(弱引用) | ✅ | ❌(弱引用) |
| size 属性 | ✅ | ❌ | ✅ | ❌ |
| GC 回收 | 不会 | 会 | 不会 | 会 |
Map
const map = new Map()
map.set('name', 'Tom')
map.set(1, 'number key') // 任意类型键
map.set({ id: 1 }, 'object key')
map.get('name') // 'Tom'
map.has('name') // true
map.size // 3
map.forEach((v, k) => console.log(k, v))Set
const set = new Set([1, 2, 2, 3, 3])
set.size // 3(自动去重)
set.add(4)
set.has(2) // true
set.delete(1)
// 数组去重
const unique = [...new Set([1, 1, 2, 3, 3])]WeakMap — 弱引用映射
const wm = new WeakMap()
let obj = { name: 'Tom' }
wm.set(obj, 'metadata')
// 当 obj 被回收,wm 中的条目也会被自动清除
obj = null // 触发 GC 后,wm 中对应条目消失使用场景
WeakMap:
- DOM 节点关联数据(节点被移除时数据自动清理)
const elementData = new WeakMap()
elementData.set(domElement, { listeners: [], state: {} })- 私有属性存储
const privateFields = new WeakMap()
class Person {
constructor(name) {
privateFields.set(this, { _name: name })
}
getName() { return privateFields.get(this)._name }
}- 缓存(对象被回收时缓存自动失效)
WeakSet:
- 对象标记(标记某对象是否被处理过)
const processed = new WeakSet()
function handle(obj) {
if (processed.has(obj)) return
// 处理 obj...
processed.add(obj)
}