JavaScript中Set添加相同对象:插入前如何判断对象是否相等?
JavaScript Set 判断对象内容相等的解决方案
JavaScript 的 Set 默认采用引用相等判断元素是否重复——也就是说,只有当两个对象是同一个引用时,Set 才会认为它们是同一个元素。这就是你代码里 person 和 person2 内容完全一致,却能被同时添加进 Set 的原因。
下面是几种在插入对象前检查内容是否“相同”的实用方法:
方法一:用 JSON.stringify 转字符串判断
将对象转为 JSON 字符串,通过判断字符串是否存在来间接检查对象内容是否重复。这种方法简单直观,但有局限性:对象里的函数、undefined、循环引用会被忽略,且键的顺序不同会导致字符串不同(比如 {a:1,b:2} 和 {b:2,a:1} 会被当成不同元素)。
let mySet = new Set(); const person = { name: 'John', age: 21 }; const person2 = { name: 'John', age: 21 }; const person3 = { age: 21, name: 'John' }; // 键顺序不同 // 封装添加逻辑 function addToSet(set, obj) { const key = JSON.stringify(obj); if (!set.has(key)) { set.add(key); return true; } return false; } addToSet(mySet, person); addToSet(mySet, person2); // 内容重复,不会添加 addToSet(mySet, person3); // 键顺序不同,会被添加 console.log([...mySet]); // 输出: ["{\"name\":\"John\",\"age\":21}","{\"age\":21,\"name\":\"John\"}"]
方法二:自定义对象相等判断函数
自己实现一个对比对象内容的函数,遍历 Set 中已有元素,逐一和待添加对象比较。这种方法可以完全自定义相等规则,比如忽略键顺序、只对比特定字段等。
let mySet = new Set(); const person = { name: 'John', age: 21 }; const person2 = { name: 'John', age: 21 }; const person3 = { name: 'John', age: 22 }; // 自定义内容相等判断函数 function isObjectEqual(objA, objB) { if (objA === objB) return true; // 引用相同直接返回true const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) return false; // 键数量不同直接排除 // 遍历所有键,对比值 for (const key of keysA) { if (objA[key] !== objB[key]) return false; } return true; } // 封装添加逻辑 function addToSet(set, obj) { for (const item of set) { if (isObjectEqual(item, obj)) { return false; // 已存在内容相同的对象 } } set.add(obj); return true; } addToSet(mySet, person); addToSet(mySet, person2); // 内容重复,不会添加 addToSet(mySet, person3); // 内容不同,会被添加 console.log(JSON.stringify([...mySet])); // 输出: [{"name":"John","age":21},{"name":"John","age":22}]
方法三:自定义哈希函数生成唯一标识
通过对象的属性生成一个稳定的哈希字符串(比如先排序键再拼接),这样可以避免 JSON.stringify 对键顺序敏感的问题,同时更灵活地控制哈希规则。
let mySet = new Set(); const person = { name: 'John', age: 21 }; const person2 = { name: 'John', age: 21 }; const person3 = { age: 21, name: 'John' }; // 键顺序不同 // 生成稳定的对象哈希值 function getObjectHash(obj) { // 先对键排序,确保键顺序不影响哈希结果 const sortedKeys = Object.keys(obj).sort(); // 拼接键和值的字符串 return sortedKeys.map(key => `${key}:${JSON.stringify(obj[key])}`).join('|'); } // 封装添加逻辑 function addToSet(set, obj) { const hash = getObjectHash(obj); if (!set.has(hash)) { set.add(hash); return true; } return false; } addToSet(mySet, person); addToSet(mySet, person2); // 哈希相同,不会添加 addToSet(mySet, person3); // 哈希相同,不会添加 console.log([...mySet]); // 输出: ["age:21|name:\"John\""]
选择建议
- 若对象结构简单、键顺序固定,优先用 JSON.stringify 方法,代码最简洁。
- 若需要自定义相等规则(比如只对比部分字段、忽略嵌套对象差异),用 自定义相等判断函数。
- 若要避免键顺序影响判断,用 自定义哈希函数 方法。
内容的提问来源于stack exchange,提问作者asfafafags
相关产品推荐
相关产品推荐

