map允许对象作键,因内部用严格相等(===)判别,不同引用即不同键;但会强引用对象阻碍gc,需手动清理,适合生命周期可控场景,weakmap才支持自动回收。

可以直接用 Map 存储对象作为键来关联元数据,但必须清楚:这会形成强引用,对象无法被垃圾回收,除非你手动清理对应条目。它适合生命周期可控、明确需要长期绑定的场景,比如缓存策略、状态管理器或模块内有限范围的对象映射。
为什么对象能当 Map 的键
Map 允许任意类型作键,包括对象、函数、Symbol 甚至 NaN。它内部通过严格相等(===)判断键是否相同,所以两个内容相同但不同引用的对象,会被视为两个独立键:
- const obj1 = { id: 1 };
- const obj2 = { id: 1 };
- map.set(obj1, 'dataA'); 和 map.set(obj2, 'dataB'); 是两条互不干扰的记录
典型使用模式:封装元数据管理器
避免直接暴露 Map 实例,推荐封装成带语义的方法,提升可维护性与安全性:
- 定义一个模块级 Map:const metaStore = new Map();
- 提供 setMeta(target, data):检查 target 是否为对象,再存入;支持覆盖或合并逻辑
- 提供 getMeta(target):返回拷贝后的数据(避免外部篡改原始值)
- 提供 clearMeta(target) 或 removeMeta(target):主动释放内存,防止泄漏
关键注意事项
对象作键不是“自动安全”的,需人工干预生命周期:
- DOM 节点、大型配置对象、组件实例等一旦作为键写入 Map,只要 Map 还持有它,GC 就不会回收——即使节点已从页面移除
- 不要把 Map 当作 WeakMap 的替代品;若目标是“随对象销毁自动清理”,WeakMap 才是唯一正解
- 遍历 Map 时可用 for...of 或 entries(),但要注意:迭代本身不会触发 GC,也不会感知键对象是否还“活着”
适用场景举例
以下情况适合用 Map + 对象键:
- 表单控件与校验规则绑定:每个 input 元素(对象引用)对应一组 rule 配置
- Canvas 图形对象与渲染状态映射:每个 shape 实例绑定 position、opacity 等运行时属性
- WebSocket 消息处理器注册:以 handler 函数为键,存储其订阅主题与回调上下文










