You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中Set存储对象无法去重的原因及实现对象唯一存储的最佳实践

问题本质

Set判断元素唯一性采用SameValueZero比较算法:对于基础类型(字符串、数字、布尔值等)按值比较,对于引用类型(对象、数组等)则按内存引用地址比较,而非对比对象的属性内容。你每次调用scrapedMessages.add()时传入的都是新创建的对象,哪怕多个对象的属性和值完全一致,它们的内存地址也不相同,因此Set会将其判定为不同元素,最终出现重复数据。

Set本身可以实现对象去重,但需要你自行定义判重的依据,以下是适配Node.js爬虫场景的可行方案和最佳实践:

推荐解决方案

方案1:业务唯一键判重(性能最优,适配你的爬虫场景)

你的爬取数据中text+senderID+timestamp三个字段可唯一标识一条消息,直接拼接这三个字段作为判重依据即可,性能远高于全对象序列化:

// 用Set存储唯一键做判重,数组存储原对象
const uniqueMsgKeys = new Set()
const scrapedMessages = []

const currentMsg = {
  text,
  ...(images.length > 0 && { images }),
  senderID,
  timestamp,
}
// 用特殊分隔符拼接,避免不同字段内容拼接后撞串
const msgUniqueKey = `${text}|||${senderID}|||${timestamp}`
if (!uniqueMsgKeys.has(msgUniqueKey)) {
  uniqueMsgKeys.add(msgUniqueKey)
  scrapedMessages.push(currentMsg)
}

方案2:排序后序列化判重(适配无明确唯一键的场景)

如果爬取的对象结构不固定,没有可直接复用的业务唯一键,可以先对对象的键排序后再序列化,避免因键顺序不同导致相同内容的对象序列化结果不一致:

const uniqueSerialized = new Set()
const scrapedMessages = []

const currentMsg = {
  text,
  ...(images.length > 0 && { images }),
  senderID,
  timestamp,
}
// 按字母顺序排序对象键后再序列化
const sortedStr = JSON.stringify(currentMsg, Object.keys(currentMsg).sort())
if (!uniqueSerialized.has(sortedStr)) {
  uniqueSerialized.add(sortedStr)
  scrapedMessages.push(currentMsg)
}

方案3:用Map实现一键存取值(适合需要直接获取唯一对象集合的场景)

如果不需要单独维护判重Set和对象数组,可以用Map存储,键为唯一标识,值为原对象,最终直接取Map的values即可得到去重后的对象集合:

const msgMap = new Map()

const currentMsg = {
  text,
  ...(images.length > 0 && { images }),
  senderID,
  timestamp,
}
const msgUniqueKey = `${text}|||${senderID}|||${timestamp}`
msgMap.set(msgUniqueKey, currentMsg)

// 最后直接导出所有唯一对象
const scrapedMessages = Array.from(msgMap.values())

最佳实践建议

  • 爬虫场景数据量通常较大,优先选择业务唯一键判重,性能比全对象序列化高1~2个数量级
  • 若必须使用序列化判重,一定要先对对象的键做排序处理,否则会出现相同内容被判定为不同的问题
  • 不要直接将普通对象存入Set做去重,除非你能保证相同内容的对象指向同一个内存引用

内容的提问来源于stack exchange,提问作者coolsaint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 19:54:03