我有2个不同的嵌套对象,我需要知道它们是否在其中一个嵌套属性中有不同。
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
对象可以更复杂,有更多嵌套的属性。但这是一个很好的例子。我可以选择使用递归函数或lodash的东西…
我有2个不同的嵌套对象,我需要知道它们是否在其中一个嵌套属性中有不同。
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
对象可以更复杂,有更多嵌套的属性。但这是一个很好的例子。我可以选择使用递归函数或lodash的东西…
当前回答
以Sridhar Gudimela的回答为基础,下面以一种使用TypeScript的方式进行了更新:
/// U T I L S
interface LooseObjectInterface {
[key: string]: any;
};
type inputOptions = LooseObjectInterface | any[];
/// E X P O R T
export const objectCompare = (objectA: inputOptions, objectB: inputOptions): LooseObjectInterface => {
let diffObj: LooseObjectInterface = {};
switch(true) {
case (Array.isArray(objectA)):
objectA.forEach((elem: any, index: number) => {
if (!Array.isArray(diffObj))
diffObj = [];
diffObj[index] = objectCompare(elem, (objectB || [])[index]);
});
break;
case (objectA !== null && typeof objectA === "object"):
Object.keys(objectA).forEach((key: any) => {
if (Array.isArray(objectA[key])) {
let arr = objectCompare(objectA[key], objectB[key]);
if (!Array.isArray(arr))
arr = [];
arr.forEach((elem: any, index: number) => {
if (!Array.isArray(diffObj[key]))
diffObj[key] = [];
diffObj[key][index] = elem;
});
} else if (typeof objectA[key] === "object")
diffObj[key] = objectCompare(objectA[key], objectB[key]);
else if (objectA[key] !== (objectB || {})[key])
diffObj[key] = objectA[key];
else if (objectA[key] === (objectB || {})[key])
delete objectA[key];
});
break;
default:
break;
}
Object.keys(diffObj).forEach((key: any) => {
if (typeof diffObj[key] === "object" && JSON.stringify(diffObj[key]) === "{}")
delete diffObj[key];
});
return diffObj;
};
编辑:我最初的回答使用了Flow,因此被否决了(我猜,或者可能是因为我的回答没有使用Lodash……)然而,有一个类似问题的答案也无妨)。
其他回答
作为对亚当·博杜赫的回答的补充,这个问题考虑到了性质的差异
const differenceOfKeys = (...objects) =>
_.difference(...objects.map(obj => Object.keys(obj)));
const differenceObj = (a, b) =>
_.reduce(a, (result, value, key) => (
_.isEqual(value, b[key]) ? result : [...result, key]
), differenceOfKeys(b, a));
下面是一个使用Lodash的简单解决方案:
_.differenceWith(a, b, _.isEqual);
注意,两个输入都需要是数组(可能是一个对象的数组)。
已经有很多答案发布,但对于那些好奇的人来说,避免编写任何代码来计算具有任何类型结构的两个对象之间的差异,实际上有一个库可以做到这一点。Lodash isEqual只返回true或false,它不返回任何关于更改属性的信息。https://www.npmjs.com/package/deep-diff
它返回两个对象之间差异的完整细节
import DeepDiff from 'deep-diff';
let a = {...} //some object
let b = {...} //some object
var differences = DeepDiff.diff(a, b);
在这篇文章中也有人提出了类似的问题 获取2个JSON对象之间的差异
深度比较使用模板的(嵌套)属性进行检查
function objetcsDeepEqualByTemplate(objectA, objectB, comparisonTemplate) {
if (!objectA || !objectB) return false
let areDifferent = false
Object.keys(comparisonTemplate).some((key) => {
if (typeof comparisonTemplate[key] === 'object') {
areDifferent = !objetcsDeepEqualByTemplate(objectA[key], objectB[key], comparisonTemplate[key])
return areDifferent
} else if (comparisonTemplate[key] === true) {
areDifferent = objectA[key] !== objectB[key]
return areDifferent
} else {
return false
}
})
return !areDifferent
}
const objA = {
a: 1,
b: {
a: 21,
b: 22,
},
c: 3,
}
const objB = {
a: 1,
b: {
a: 21,
b: 25,
},
c: true,
}
// template tells which props to compare
const comparisonTemplateA = {
a: true,
b: {
a: true
}
}
objetcsDeepEqualByTemplate(objA, objB, comparisonTemplateA)
// returns true
const comparisonTemplateB = {
a: true,
c: true
}
// returns false
objetcsDeepEqualByTemplate(objA, objB, comparisonTemplateB)
这将在控制台中工作。如果需要,可以添加数组支持
我尝试了Adam Boduch的代码来输出一个很深的差异-这完全没有经过测试,但碎片在那里:
function diff (obj1, obj2, path) {
obj1 = obj1 || {};
obj2 = obj2 || {};
return _.reduce(obj1, function(result, value, key) {
var p = path ? path + '.' + key : key;
if (_.isObject(value)) {
var d = diff(value, obj2[key], p);
return d.length ? result.concat(d) : result;
}
return _.isEqual(value, obj2[key]) ? result : result.concat(p);
}, []);
}
diff({ foo: 'lol', bar: { baz: true }}, {}) // returns ["foo", "bar.baz"]