ES6 WeakMap 生效的证明: FinalizationRegistry

为什么要有 Map 和 WeakMap?

普通对象的 key只能是 字符串 或者 Symbol。

没有办法使用 Object 作为对象。

和传统的对象比,Map和WeakMap的优点

  • map中的各映射是有顺序的,object是没有
  • 传统的object对象只能用【字符串、Symbol】作key(键值),而map甚至可以用对象作key值。
  • 上面的第二点其实会造成很严重的问题,这意味着我们没法区分 1 和 '1'

WeakMap - JavaScript | MDN

【弱引用】:在没有其他引用的时候,垃圾回收正常进行。

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 正确回收。

相关推荐
程序员海军1 小时前
用了两年多 GPT,我最近开始换模型了,还折腾了个求职避坑 Agent
前端·人工智能·后端
zttbee2 小时前
echarts图表tooltip色块失效
前端·javascript·echarts
excel3 小时前
IndexNow:让搜索引擎更快发现网站更新的主动通知协议
前端·后端·架构
子兮曰4 小时前
CSS 复现 23 种设计风格:从拟物到液态玻璃的成本阶梯与兜底写法【实战】
前端·css·视觉设计
虚无境4 小时前
如何用AI帮我写出实用的插件
前端·javascript·ai编程
柳杉5 小时前
从数字化到数智化:3D 可视化大屏的下一个五年
前端·ai编程·数据可视化
zimoyin5 小时前
在 C# 里嵌入 JavaScript:用 Jint 做可热更新的自动化脚本(从入门到踩坑)
javascript·c#·自动化
风骏时光牛马6 小时前
从零到实战:AI全栈学习进阶路线
前端
FRing036 小时前
JavaScript入门到精通二十六(变量提升、函数剩余参数、展开运算符、ES6箭头函数)
开发语言·前端·javascript·es6·箭头函数
用户360055579006 小时前
Kestrel_VLLM - 15 · decode 优化四连击:19ms → 8ms
前端