我有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的东西…
当前回答
如果你只需要键比较:
_.reduce(a, function(result, value, key) {
return b[key] === undefined ? key : []
}, []);
其他回答
一个简单而优雅的解决方案是使用_。isEqual,它执行深度比较:
Var a = {}; Var b = {}; A.prop1 = 2; A.prop2 = {prop3: 2}; B.prop1 = 2; B.prop2 = {prop3: 3}; console.log(_。isEqual (a, b));//如果不同则返回false < script src = " https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js " > < /脚本>
然而,这个解决方案并没有显示哪个属性是不同的。
这是基于@JLavoie,使用lodash
let differences = function (newObj, oldObj) {
return _.reduce(newObj, function (result, value, key) {
if (!_.isEqual(value, oldObj[key])) {
if (_.isArray(value)) {
result[key] = []
_.forEach(value, function (innerObjFrom1, index) {
if (_.isNil(oldObj[key][index])) {
result[key].push(innerObjFrom1)
} else {
let changes = differences(innerObjFrom1, oldObj[key][index])
if (!_.isEmpty(changes)) {
result[key].push(changes)
}
}
})
} else if (_.isObject(value)) {
result[key] = differences(value, oldObj[key])
} else {
result[key] = value
}
}
return result
}, {})
}
https://jsfiddle.net/EmilianoBarboza/0g0sn3b9/8/
如果你需要知道哪些属性是不同的,使用reduce():
_.reduce(a, function(result, value, key) {
return _.isEqual(value, b[key]) ?
result : result.concat(key);
}, []);
// → [ "prop2" ]
以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 _ = require('lodash');
var objects = [{ 'x': 1, 'y': 2, 'z':3, a:{b:1, c:2, d:{n:0}}, p:[1, 2, 3] }, { 'x': 2, 'y': 1, z:3, a:{b:2, c:2,d:{n:1}}, p:[1,3], m:3 }];
const diffFn=(a,b, path='')=>_.reduce(a, function(result, value, key) {
if(_.isObjectLike(value)){
if(_.isEqual(value, b[key])){
return result;
}else{
return result.concat(diffFn(value, b[key], path?(`${path}.${key}`):key))
}
}else{
return _.isEqual(value, b[key]) ?
result : result.concat(path?(`${path}.${key}`):key);
}
}, []);
const diffKeys1=diffFn(objects[0], objects[1])
const diffKeys2=diffFn(objects[1], objects[0])
const diffKeys=_.union(diffKeys1, diffKeys2)
const res={};
_.forEach(diffKeys, (key)=>_.assign(res, {[key]:{ old: _.get(objects[0], key), new:_.get(objects[1], key)} }))
res
/*
Returns
{
x: { old: 1, new: 2 },
y: { old: 2, new: 1 },
'a.b': { old: 1, new: 2 },
'a.d.n': { old: 0, new: 1 },
'p.1': { old: 2, new: 3 },
'p.2': { old: 3, new: undefined },
m: { old: undefined, new: 3 }
}
*/