我有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, (r, v, k) => { return _.merge(r, _.isEqual(v, b[k]) ? {} : { [k]: v }); }, {});
其他回答
我需要知道它们的某个嵌套属性是否不同
其他答案为这个问题提供了可能令人满意的解决方案,但它非常困难和常见,似乎有一个非常受欢迎的包来帮助解决这个问题。
要使用这个包,你需要npm i deep-object-diff,然后:
const { diff } = require('deep-object-diff');
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
if (!_.isEqual(a, b)) {
const abDiff = diff(a, b);
console.log(abDiff);
/*
{
prop2: {
prop3: 3
}
}
*/
}
// or alternatively
const abDiff = diff(a, b);
if(!_.isEmpty(abDiff)) {
// if a diff exists then they aren't deeply equal
// perform needed actions with diff...
}
下面是一个更详细的案例,直接从他们的文档中删除属性:
const lhs = {
foo: {
bar: {
a: ['a', 'b'],
b: 2,
c: ['x', 'y'],
e: 100 // deleted
}
},
buzz: 'world'
};
const rhs = {
foo: {
bar: {
a: ['a'], // index 1 ('b') deleted
b: 2, // unchanged
c: ['x', 'y', 'z'], // 'z' added
d: 'Hello, world!' // added
}
},
buzz: 'fizz' // updated
};
console.log(diff(lhs, rhs)); // =>
/*
{
foo: {
bar: {
a: {
'1': undefined
},
c: {
'2': 'z'
},
d: 'Hello, world!',
e: undefined
}
},
buzz: 'fizz'
}
*/
有关实现细节和其他使用信息,请参阅该repo。
下面是一个使用Lodash的简单解决方案:
_.differenceWith(a, b, _.isEqual);
注意,两个输入都需要是数组(可能是一个对象的数组)。
我们需要在两个json更新之间获取delta,以跟踪数据库更新。也许其他人会觉得这很有用。
https://gist.github.com/jp6rt/7fcb6907e159d7851c8d59840b669e3d
const {
isObject,
isEqual,
transform,
has,
merge,
} = require('lodash');
const assert = require('assert');
/**
* Perform a symmetric comparison on JSON object.
* @param {*} baseObj - The base object to be used for comparison against the withObj.
* @param {*} withObj - The withObject parameter is used as the comparison on the base object.
* @param {*} invert - Because this is a symmetric comparison. Some values in the with object
* that doesn't exist on the base will be lost in translation.
* You can execute again the function again with the parameters interchanged.
* However you will lose the reference if the value is from the base or with
* object if you intended to do an assymetric comparison.
* Setting this to true will do make sure the reference is not lost.
* @returns - The returned object will label the result of the comparison with the
* value from base and with object.
*/
const diffSym = (baseObj, withObj, invert = false) => transform(baseObj, (result, value, key) => {
if (isEqual(value, withObj[key])
&& has(withObj, key)) {
return;
}
if (isObject(value)
&& isObject(withObj[key])
&& !Array.isArray(value)) {
result[key] = diffSym(value, withObj[key], invert);
return;
}
if (!invert) {
result[key] = {
base: value,
with: withObj[key],
};
return;
}
if (invert) {
result[key] = {
base: withObj[key],
with: value,
};
}
});
/**
* Perform a assymmetric comparison on JSON object.
* @param {*} baseObj - The base object to be used for comparison against the withObj.
* @param {*} withObj - The withObject parameter is used as the comparison on the base object.
* @returns - The returned object will label the values with
* reference to the base and with object.
*/
const diffJSON = (baseObj, withObj) => {
// Deep clone the objects so we don't update the reference objects.
const baseObjClone = JSON.parse(JSON.stringify(baseObj));
const withObjClone = JSON.parse(JSON.stringify(withObj));
const beforeDelta = diffSym(baseObjClone, withObjClone);
const afterDelta = diffSym(withObjClone, baseObjClone, true);
return merge(afterDelta, beforeDelta);
};
// By Example:
const beforeDataObj = {
a: 1,
c: { d: 2, f: 3 },
g: 4,
h: 5,
};
const afterDataObj = {
a: 2,
b: 3,
c: { d: 1, e: 1 },
h: 5,
};
const delta = diffJSON(beforeDataObj, afterDataObj);
// Assert expected result.
assert(isEqual(delta, {
a: { base: 1, with: 2 },
b: { base: undefined, with: 3 },
c: {
d: { base: 2, with: 1 },
e: { base: undefined, with: 1 },
f: { base: 3, with: undefined },
},
g: { base: 4, with: undefined },
}));
我知道这并不能直接回答OP的问题,但我是通过搜索如何删除lodash被引导到这里的。希望这能帮助到和我处境相似的人。
这要归功于@JohanPersson。我在这个答案的基础上实现了对深度嵌套值的比较,并获得对差异的键引用
getObjectDiff = (obj1, obj2) => { const obj1Props = Object.keys(obj1); const obj2Props = Object.keys(obj2); const keysWithDiffValue = obj1Props.reduce((keysWithDiffValueAccumulator, key) => { const propExistsOnObj2 = obj2.hasOwnProperty(key); const hasNestedValue = obj1[key] instanceof Object && obj2[key] instanceof Object; const keyValuePairBetweenBothObjectsIsEqual = obj1[key] === obj2[key]; if (!propExistsOnObj2) { keysWithDiffValueAccumulator.push(key); } else if (hasNestedValue) { const keyIndex = keysWithDiffValueAccumulator.indexOf(key); if (keyIndex >= 0) { keysWithDiffValueAccumulator.splice(keyIndex, 1); } const nestedDiffs = getObjectDiff(obj1[key], obj2[key]); for (let diff of nestedDiffs) { keysWithDiffValueAccumulator.push(`${key}.${diff}`); } } else if (keyValuePairBetweenBothObjectsIsEqual) { const equalValueKeyIndex = keysWithDiffValueAccumulator.indexOf(key); keysWithDiffValueAccumulator.splice(equalValueKeyIndex, 1); } return keysWithDiffValueAccumulator; }, obj2Props); return keysWithDiffValue; } const obj1 = {a0: {a1: {a2: {a3: 'Im here'}}}}; const obj2 = {a0: {a1: {a2: {a3: 'Not here', b3: 'some'}}}}; console.log('final', getObjectDiff(obj1, obj2));
这是一个简单的带有Lodash深度差异检查器的Typescript,它将生成一个新对象,只包含旧对象和新对象之间的差异。
例如,如果我们有:
const oldData = {a: 1, b: 2};
const newData = {a: 1, b: 3};
结果对象将是:
const result: {b: 3};
它还兼容多层深层对象,对于数组,它可能需要一些调整。
import * as _ from "lodash";
export const objectDeepDiff = (data: object | any, oldData: object | any) => {
const record: any = {};
Object.keys(data).forEach((key: string) => {
// Checks that isn't an object and isn't equal
if (!(typeof data[key] === "object" && _.isEqual(data[key], oldData[key]))) {
record[key] = data[key];
}
// If is an object, and the object isn't equal
if ((typeof data[key] === "object" && !_.isEqual(data[key], oldData[key]))) {
record[key] = objectDeepDiff(data[key], oldData[key]);
}
});
return record;
};