map和set报错主因是场景误用、行为误解或忽略机制;排查应聚焦值类型、引用关系、序列化需求三点。

Map 和 Set 本身语法简单,报错往往不是写错了 API,而是用错了场景、误解了行为,或忽略了底层机制。排查时别急着查文档方法名,先盯住“值的类型”“引用关系”“序列化需求”这三个关键点。
报错:JSON.stringify 后变成空对象 {}
这是最常被问到的问题。Map 和 Set 没有可枚举的自有属性,JSON.stringify 只遍历 plain object 的键和 array 的索引,所以直接序列化结果永远是 {}。
- 正确做法:手动转成普通结构再序列化,例如
Object.fromEntries(map)或[...set] - 注意:如果 Map 的 key 是对象或函数,
Object.fromEntries会报错(不能把对象转为字符串 key),此时必须先做 key 的标准化(如用id字段或JSON.stringify序列化) - 若含循环引用,还需额外处理,比如在自定义
toJSON()方法中剥离或替换非标准值
报错:Set.has() 返回 false,但元素明明“看起来一样”
根本原因在于 Set 使用 SameValueZero 算法判等,不是深比较,也不是字符串转换——它只对基本类型和 NaN 友好,对对象、数组等引用类型,只看内存地址是否相同。
-
new Set([{a:1}, {a:1}]).has({a:1})一定返回false,因为每次写的{a:1}都是新对象 - 需要按内容去重?得自己实现逻辑:比如用
Map存JSON.stringify(obj) → obj映射,或借助第三方库做深判等 - 检查是否误把
null和undefined当作相同值——它们在 Set 中是两个独立元素
报错:Map.set(obj, value) 后内存不释放,导致内存泄漏
Map 对 key 和 value 都是强引用。如果你把 DOM 元素、React 组件实例、大型数据对象作为 key 存进 Map,而这些对象本该被回收,Map 却一直拽着它们不放,就会引发内存持续增长。
- 判断依据:用 Chrome DevTools 的 Memory 面板录制堆快照,筛选出大量未释放的 DOM 节点或组件类实例,并查看 retainers 是否指向某个 Map 实例
- 解决方案:改用
WeakMap——它的 key 必须是对象,且是弱引用,一旦对象在别处失去所有强引用,WeakMap 中对应条目自动消失 - 注意:WeakMap 不支持遍历、没有
.size、不能用基本类型作 key,适用场景有限(如私有状态、缓存计算结果)
报错:遍历时顺序混乱,或 forEach 参数顺序搞反
Map 的 forEach 是 (value, key, map),Set 的 forEach 是 (value, value, set)——第二个参数不是索引,这点和数组完全不同,容易传错参数导致逻辑异常。
- 混淆示例:
map.forEach((key, value) => {...})会把 value 当 key 用,造成取值错误 - Map 遍历保证插入顺序,但 Object 在早期引擎或混合数字/字符串 key 时顺序不可靠;若你依赖顺序,就别用 Object 替代 Map
- 用
for...of更安全:Map 迭代出[key, value]数组,Set 迭代出单个值,语义清晰不易错











