在JavaScript开发中,经常会遇到需要对比两个JSON数组的场景,比如前端获取到的本地缓存数据和最新的服务端数据对比,或者表单修改前后的数据差异校验,核心需求就是找出两个数组中不同的元素,包括仅存在于第一个数组的新增元素、仅存在于第二个数组的删除元素,以及两个数组中都存在但属性有变化的数据。

基础对比:基于唯一标识提取差异
如果JSON数组中的每个元素都有唯一标识字段,比如id,那么对比逻辑会简单很多,我们可以通过唯一标识快速判断元素的归属。
提取仅存在于第一个数组的元素
思路是先收集第二个数组所有唯一标识,再遍历第一个数组过滤出标识不在第二个数组中的元素。
// 定义两个待对比的JSON数组
const arr1 = [
{ id: 1, name: '张三', age: 20 },
{ id: 2, name: '李四', age: 22 },
{ id: 3, name: '王五', age: 25 }
];
const arr2 = [
{ id: 2, name: '李四', age: 23 },
{ id: 3, name: '王五', age: 25 },
{ id: 4, name: '赵六', age: 28 }
];
// 提取arr2中所有的id集合
const arr2Ids = new Set(arr2.map(item => item.id));
// 仅存在于arr1中的元素
const onlyInArr1 = arr1.filter(item => !arr2Ids.has(item.id));
console.log('仅存在于第一个数组的元素:', onlyInArr1);
提取仅存在于第二个数组的元素
同理,我们收集第一个数组的唯一标识,再过滤第二个数组即可。
// 提取arr1中所有的id集合
const arr1Ids = new Set(arr1.map(item => item.id));
// 仅存在于arr2中的元素
const onlyInArr2 = arr2.filter(item => !arr1Ids.has(item.id));
console.log('仅存在于第二个数组的元素:', onlyInArr2);
深度对比:处理属性变化的差异
如果数组元素没有唯一标识,或者需要对比元素属性的变化,就需要用到深度比较的方法。这里我们可以使用JSON.stringify做简单的序列化对比,也可以使用更严谨的深度比较函数。
使用JSON.stringify做简单对比
这种方式适合数组元素结构比较简单的场景,注意如果对象属性顺序不同,JSON.stringify的结果会不一样,可能导致误判。
// 简单深度比较函数,使用JSON.stringify实现
function isSameObj(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
// 找出arr1中和arr2所有元素都不相同的元素
const diffInArr1 = arr1.filter(item1 => {
return !arr2.some(item2 => isSameObj(item1, item2));
});
console.log('arr1中和arr2不同的元素:', diffInArr1);
自定义深度比较函数
如果对象属性顺序可能不同,或者需要处理更复杂的数据类型,我们可以自定义深度比较函数。
// 自定义深度比较函数
function deepEqual(obj1, obj2) {
// 基本类型直接比较
if (obj1 === obj2) return true;
// 类型不同直接返回false
if (typeof obj1 !== typeof obj2) return false;
// 处理null的情况
if (obj1 == null || obj2 == null) return false;
// 处理数组
if (Array.isArray(obj1) && Array.isArray(obj2)) {
if (obj1.length !== obj2.length) return false;
for (let i = 0; i < obj1.length; i++) {
if (!deepEqual(obj1[i], obj2[i])) return false;
}
return true;
}
// 处理对象
if (typeof obj1 === 'object' && typeof obj2 === 'object') {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (const key of keys1) {
if (!deepEqual(obj1[key], obj2[key])) return false;
}
return true;
}
return false;
}
// 使用自定义深度比较函数找差异
const diffArr1 = arr1.filter(item1 => {
return !arr2.some(item2 => deepEqual(item1, item2));
});
const diffArr2 = arr2.filter(item2 => {
return !arr1.some(item1 => deepEqual(item1, item2));
});
console.log('arr1中独有的元素:', diffArr1);
console.log('arr2中独有的元素:', diffArr2);
提取属性变化的差异数据
如果我们不仅想知道元素是否存在差异,还想知道具体哪些属性发生了变化,可以结合唯一标识和深度比较实现。
// 找出两个数组中都存在但属性有变化的元素
const changedItems = [];
arr1.forEach(item1 => {
const target = arr2.find(item2 => item2.id === item1.id);
if (target && !deepEqual(item1, target)) {
// 找出变化的属性
const changedKeys = {};
Object.keys(item1).forEach(key => {
if (item1[key] !== target[key]) {
changedKeys[key] = {
oldValue: item1[key],
newValue: target[key]
};
}
});
changedItems.push({
id: item1.id,
changes: changedKeys
});
}
});
console.log('属性变化的元素:', changedItems);
不同场景的方案选择
我们可以根据实际场景选择不同的对比方案:
- 如果数组元素有唯一标识,优先使用基于唯一标识的对比方案,时间复杂度低,效率更高
- 如果元素没有唯一标识且结构简单,可以使用
JSON.stringify的序列化对比 - 如果元素结构复杂、属性顺序可能不一致,建议使用自定义深度比较函数
- 如果需要知道具体属性变化内容,结合唯一标识和属性遍历的方案实现
以上几种方案覆盖了大部分JavaScript中对比JSON数组并提取差异的场景,开发者可以根据实际需求选择合适的实现方式,也可以将对应的函数封装成工具函数方便后续复用。
JavaScriptJSON数组数组比较差异提取修改时间:2026-06-19 02:57:42