前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库WeakMap 键对象 垃圾回收影响
JavaScript数组与集合

WeakMap 的键只能是对象吗,它怎样影响垃圾回收?

WeakMap 的键必须是能被垃圾回收的值:对象,以及 ES2023 起允许的非注册 Symbol。字符串、数字这些原始值不行,Symbol.for() 创建的注册 Symbol 也不行。它不会因为自己存着键就阻止键被回收,键对象在别处没有引用了,对应的条目也会跟着消失。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数组与集合#缓存
先看核心答案读代码示例
理解线索

`WeakMap` 和对象的生命周期绑在一起

  1. 键对象或非注册 Symbol,按引用查找
  2. 弱引用键在别处没有强引用时,条目可以被回收
  3. 不可枚举没有 keys() 和 size,回收时机不会暴露出来

键没有其他引用后只是「可以被回收」,什么时候真正回收由引擎决定。业务逻辑不能依赖回收时机,比如指望过几秒条目就没了。

核心回答

先记住这个答案

WeakMap 的键过去只能是对象,ES2023 起也可以是非注册的 Symbol,也就是用 Symbol() 创建的那种。字符串、数字这些原始值不能当键,Symbol.for() 创建的注册 Symbol 也不行,因为它们永远不会被回收。WeakMap 对键是弱引用:它存着这个键,但不算作「还有人在用」。键对象在程序别处没有引用了,垃圾回收器就可以回收它,对应的条目也一起消失。因为条目随时可能消失,WeakMap 没有 size,也不能遍历,只能拿着已知的键去 get、has、set、delete。

  • 键只能是对象或非注册 Symbol
  • 对键是弱引用,不会阻止键对象被回收
  • 没有 size,也不能遍历,只能按已知的键查
  • 适合给对象挂附加数据,不适合做需要淘汰策略的缓存

键的限制:对象按引用,原始值不行

下面给一个任务对象挂上附加数据,再试试用字段相同的新对象查,以及两种 Symbol 当键的情况。

对象键和 Symbol 键JavaScript
const metadata = new WeakMap()
const task = { id: 1 }

metadata.set(task, { checked: true })
console.log(metadata.get(task).checked)
console.log(metadata.has({ id: 1 }))          // 新对象,不是同一个键

const token = Symbol('local')
metadata.set(token, 'allowed')                // 非注册 Symbol 可以当键
console.log(metadata.get(token))

try {
  metadata.set(Symbol.for('shared'), 'invalid')  // 注册 Symbol 不行
} catch (error) {
  console.log(error.name)
}
查看输出与解释
true
false
allowed
TypeError

has({ id: 1 }) 是 false,因为键按引用比较,字段一样的新对象是另一个键。Symbol('local') 每次创建都是唯一的,没有引用后可以被回收,所以能当键。Symbol.for('shared') 存在全局注册表里,任何地方都能再取到它,永远不会被回收,放进 WeakMap 就失去了弱引用的意义,所以直接抛 TypeError。

为什么需要弱引用

假设要给页面上的 DOM 节点记录一些状态,比如某个节点被点击了几次。用 Map 存的话,节点从页面上移除后,Map 里还引用着它,节点和它的数据都释放不了,这就是内存泄漏。换成 WeakMap,节点在别处没有引用后,条目会自动被回收,不用手动清理。

适合和不适合的场景
适合的场景有两类。一是给别人的对象附加数据,又不想改对象本身,比如缓存某个对象的计算结果,对象没了缓存也就没了。二是存类实例的私有数据,在 # 私有字段出现之前,这是常见的写法。 不适合的场景是需要控制容量的缓存。WeakMap 不能遍历,没法实现「最多存 100 条,超了淘汰最久没用的」这种策略,这时要用 Map 自己管理。
回答前,多想一步

容易答错的地方

还在说 WeakMap 的键只能是对象
这是 ES2023 之前的说法。现在非注册 Symbol 也可以当键,注册 Symbol 仍然不行。回答时可以补一句:老版本的运行环境可能还不支持 Symbol 键,用之前要确认。
以为 WeakMap 会弱引用值
弱引用的只是键。值由条目强引用着,键活着值就一直在;键被回收后,值如果没有别的地方引用,也会被回收。值里反过来引用了键,也不会导致键回收不掉,WeakMap 专门处理了这种情况。
把对象设为 null 就认为内存马上释放了
obj = null 只是去掉了一个引用,别处可能还有引用,比如闭包、事件监听、数组里。即使没有任何引用了,什么时候回收也由引擎决定。
试着用自己的话回答

面试官还会怎么问?

WeakMap 为什么不能遍历,也没有 size?

条目什么时候消失取决于垃圾回收,而回收时机是不确定的。如果能遍历或计数,同一段代码在不同时刻会得到不同的结果,程序行为就依赖于回收时机了,所以规范故意不提供这些能力。

值可以是字符串或数字吗?

可以。限制只针对键,值可以是任何类型。

WeakMap 能替代组件卸载时的清理逻辑吗?

不能。它只负责让数据跟着键一起被回收,不会帮你调用取消订阅、清除定时器、关闭连接这些操作。组件卸载时该做的清理还是要显式写,比如在 useEffect 的清理函数里。

从一道题,走向一组知识

把知识连起来

数组与集合

WeakSet 适合用来标记对象已处理吗,它和 Set 有什么不同?

只需要记录一个对象「处理过没有」,不需要存值时,用 WeakSet 更合适。

数组与集合

Map.size 和 Object.keys(obj).length 数的到底是什么?

Map 有 size 能计数,WeakMap 故意不提供,那篇讲各种集合的计数方式。

参考资料

  • MDN:WeakMap

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 键的限制:对象按引用,原始值不行
  3. 为什么需要弱引用
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑