为什么要有 Map 和 WeakMap?
普通对象的 key只能是 字符串 或者 Symbol。
没有办法使用 Object 作为对象。
和传统的对象比,Map和WeakMap的优点
- map中的各映射是有顺序的,object是没有
- 传统的object对象只能用【字符串、Symbol】作key(键值),而map甚至可以用对象作key值。
- 上面的第二点其实会造成很严重的问题,这意味着我们没法区分 1 和 '1'
【弱引用】:在没有其他引用的时候,垃圾回收正常进行。

WeakMap 垃圾回收演示
javascript
const register = new FinalizationRegistry((value) => {
console.log('🍀🍀🍀🍀 回收了', value)
})
let key = {
obj: 'chp',
}
const m = new WeakMap()
m.set(key, 1)
register.register(key)
key = null
gc() // 🍀🍀🍀🍀 回收了 undefined
对于 WeakMap 来说,__obj__由于通过标记清除的方式,从全局对象找不到了,WeakMap的引用不会影响循环引用对象的【被清理】。
有利于节约内存。
并且本身,WeakMap的占用就比 Map 要小。(毕竟是阉割版本的 Map,只有 get/set/has/delete)。
如官网所说,就像上面的例子一样。
如果 obj 本身就是你想要清除的。
然后又默认触发了GC(假设自动发生了这件事情)。
那么你通过 WeakMap.get 就得不到你想要的值了 => 这种时候你要用 Map 。
应用场景
- 深拷贝------循环引用
- 性能需求较高的场景
WeakMap 更节省空间的证明
占用的变量更小
scss
function printMermory() {
let used = 0
return function (isPrint) {
let nowUsed = process.memoryUsage().heapUsed
if (isPrint) {
console.log('🍀🍀🍀🍀 总共减少了', (used - nowUsed) / 1024 / 1024)
} else {
used = nowUsed
}
}
}
const cost = printMermory()
function testMap() {
const map = new Map()
let keys = []
for (let i = 0; i < 10000; i++) {
const key = { index: i }
keys.push(key)
map.set(key, 1)
}
cost()
keys = null
setTimeout(() => {
gc()
}, 0)
setTimeout(() => {
console.log('🍀🍀🍀🍀', '内存释放之后')
cost(true)
}, 3000)
}
function testWeakMap() {
const map = new WeakMap()
let keys = []
for (let i = 0; i < 10000; i++) {
const key = { index: i }
keys.push(key)
map.set(key, 1)
}
cost()
keys = null
setTimeout(() => {
gc()
}, 0)
setTimeout(() => {
console.log('🍀🍀🍀🍀', '内存释放之后')
cost(true)
}, 3000)
}
// testMap() // 总共减少了 1.170097351074218
testWeakMap() // 总共减少了 0.75359
分别在 Node 环境中执行上面的代码,可以看到,WeakMap 占据的空间更少
css
node --expose-gc weakMap3.js
弱引用的证明
javascript
const register = new FinalizationRegistry((value) => {
console.log('🍀🍀🍀🍀 回收了', value)
})
let key = {
obj: 'chp',
}
register.register(key)
const weakIns = new WeakMap()
// weakIns.set(key, 1) // 当然,这里的 key 是可以被回收的
const ins = new Map()
// ins.set(key, 1) // 可以看到,只有 weakMap 会被回收
key = null
gc() // 🍀🍀🍀🍀 回收了 undefined
我们轮流打开 weakIns 和 ins。【注意不要同时打开,因为只要 Map() 打开了,key 为 null 的时候,key是不会被回收的。因为由于引用计数的原因,此时 key 被 Map 引用】
而 WeakMap 就不会有这个问题。
注释 Map,可以发现 当 key = null 的时候,直接被 gc 正确回收。