javascript对象数组去重需标准化表示:方法一按键排序后json.stringify,适合浅层对象;方法二用深比较(如lodash.isequal),适合嵌套或特殊类型;方法三自定义哈希键,支持灵活定制规则。

JavaScript 中对对象数组去重时,若想忽略属性顺序(比如 {a: 1, b: 2} 和 {b: 2, a: 1} 视为相同),不能直接用 JSON.stringify(),因为对象键序不同会导致字符串不同。核心思路是:**标准化对象表示**——把对象转成「与键序无关」的可比形式。
方法一:按键名排序后序列化
将对象的键按字母顺序排序,再转为 JSON 字符串,确保结构一致:
说明:先提取所有键并排序,再按序构建新对象或生成有序字符串;适合浅层对象,不处理嵌套、函数、undefined 等。
- 用
Object.keys(obj).sort()获取排序后的键数组 - 用
reduce或Object.fromEntries构造键序统一的对象 - 再用
JSON.stringify得到稳定字符串
示例代码:
function normalizeObj(obj) {
const sortedKeys = Object.keys(obj).sort();
const sortedEntries = sortedKeys.map(key => [key, obj[key]]);
return JSON.stringify(Object.fromEntries(sortedEntries));
}
const arr = [
{ a: 1, b: 2 },
{ b: 2, a: 1 },
{ c: 3, a: 1 }
];
const unique = [...new Map(arr.map(item => [normalizeObj(item), item])).values()];
// → [{a:1,b:2}, {a:1,c:3}]
方法二:用深比较做逻辑去重(推荐用于复杂对象)
不依赖字符串化,而是用深相等判断两个对象是否“内容一致”,再手动过滤:
说明:适合含嵌套、数组、null、数字/字符串值等场景;需引入轻量库(如 lodash.isEqual)或手写简易深比较(不推荐处理循环引用)。
- 遍历数组,对每个对象与已存结果逐个调用
isEqual - 仅当无匹配时才加入结果数组
- 避免序列化陷阱,语义更准确
示例(使用 Lodash):
import { isEqual } from 'lodash';
function uniqByDeepEqual(arr) {
return arr.filter((item, index) =>
index === arr.findIndex(other => isEqual(other, item))
);
}
方法三:自定义哈希键(进阶,可控性强)
为每个对象生成唯一且顺序无关的哈希字符串,例如基于键值对集合的排序字符串:
说明:比单纯 JSON.stringify 更健壮,可扩展支持类型转换、忽略特定字段、处理 NaN 等。
- 把对象转为
[key, value]数组,对 key 排序 - 对 value 做安全序列化(如
JSON.stringify(value),或特殊处理 Date / RegExp) - 拼接所有
"key:value"对,用分隔符连接(如|)
简化版实现:
function getHash(obj) {
return Object.entries(obj)
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}:${JSON.stringify(v)}`)
.join('|');
}
const map = new Map();
arr.forEach(item => map.set(getHash(item), item));
const unique = [...map.values()];
注意事项
注意点:所有方法都不处理函数、undefined、Symbol、Date 对象默认序列化问题。若数据含这些类型,需提前转换(如 Date → ISO 字符串,函数 → null)或改用深比较方案。
- 浅层对象 + 简单值 → 用方法一(排序+stringify)最轻量
- 含嵌套/特殊类型/需语义准确 → 用方法二(
isEqual)最稳妥 - 需要定制规则(如忽略某些字段、容错 NaN)→ 用方法三(自定义哈希)最灵活
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











