JS使用Map统计对象数组重复次数时无法识别重复值的问题
问题根因
JavaScript中对象属于引用类型,Map的键匹配规则采用SameValueZero相等判定:对于引用类型值,只有两个变量指向内存中同一个对象实例时,才会被判定为相等。
你数组中属性完全一致的重复书籍对象,本质是独立创建的不同实例,内存地址互不相同,因此每次执行mp.has(obj)都会返回false,最终所有条目计数都为1。
另外你的原代码存在一个隐性问题:for...of循环内的obj未做变量声明,会污染全局作用域,建议补充const声明。
可行解决方案
方案1:拼接业务唯一标识作为Map键(推荐,性能最优)
书籍的书名+作者组合可以作为唯一识别依据,将二者拼接为字符串作为Map的键,从根源上避免引用类型判断的问题。注意拼接时加入不会出现在书名/作者名中的特殊分隔符,避免不同字段拼接后产生歧义。
const mp = new Map() for (const obj of collection) { // 用 || 作为分隔符,避免字段值拼接冲突 const uniqueKey = `${obj.Title}||${obj.Author}` mp.set(uniqueKey, (mp.get(uniqueKey) || 0) + 1) } // 如果需要最终输出对象与计数的映射,可遍历Map做结构转换 const countList = [] for (const [key, count] of mp) { const [Title, Author] = key.split('||') countList.push({ book: { Title, Author }, count }) }
方案2:序列化对象作为键(适合属性固定的简单对象)
如果对象属性顺序固定、无循环引用、无函数/undefined等特殊值,可以直接用JSON.stringify将对象序列化为字符串作为键,代码更简洁:
const mp = new Map() for (const obj of collection) { const key = JSON.stringify(obj) mp.set(key, (mp.get(key) || 0) + 1) }
注意:如果两个对象属性顺序不同,哪怕属性值完全一致,
JSON.stringify生成的字符串也会不同,会导致统计错误,使用前请确认数据源的对象属性顺序一致。
方案3:遍历对比属性(适合数据量小的场景)
如果不想生成额外的键,也可以在每次遍历的时候手动对比已统计对象的属性值,数据量较大时该方法性能较差,不推荐处理大体积txt解析后的数据集:
const countResult = [] for (const obj of collection) { const exist = countResult.find(item => item.book.Title === obj.Title && item.book.Author === obj.Author ) if (exist) { exist.count += 1 } else { countResult.push({ book: obj, count: 1 }) } }
内容的提问来源于stack exchange,提问作者rheanaomi
相关产品推荐
相关产品推荐

