我有两个嵌套对象obj1
和obj2
,我想将它们进行比较,然后递归地返回一个对象,该对象的每个嵌套键都有一个类似相等的布尔值标志
因此对于给定的obj1
喜欢
obj1 = {
prop1: 1,
prop2: "foo",
prop3: {
prop4: 2,
prop5: "bar"
}
}
和obj2
之类的
obj2 = {
prop1: 3,
prop2: "foo",
prop3: {
prop4: 2,
prop5: "foobar"
},
prop6: "new"
}
它应该返回
equality = {
prop1: false,
prop2: true,
prop3 : {
prop4: true,
prop5: false
},
prop6: false
}
如果对象具有新属性,例如obj2.prop6
,则等式为equality.prop6 = false
。
对于非嵌套对象,这里是一个简单的键比较解决方案Get the property of the difference between two objects in javascript 在递归比较嵌套对象时,此处显示JavaScript: Deep comparison recursively: Objects and properties
答案 0 :(得分:5)
如果两个值都是对象,则可以迭代所有键并检查嵌套的对象。
const isObject = v => v && typeof v === 'object';
function getDifference(a, b) {
return Object.assign(...Array.from(
new Set([...Object.keys(a), ...Object.keys(b)]),
k => ({ [k]: isObject(a[k]) && isObject(b[k])
? getDifference(a[k], b[k])
: a[k] === b[k]
})
));
}
var obj1 = { prop1: 1, prop2: "foo", prop3: { prop4: 2, prop5: "bar" } },
obj2 = { prop1: 3, prop2: "foo", prop3: { prop4: 2, prop5: "foobar" }, prop6: "new" };
console.log(getDifference(obj1, obj2));
答案 1 :(得分:2)
浏览每个键并比较属性。如果该属性是一个对象,则递归比较这些属性。这将适用于任何级别的嵌套。由于两个对象之一value || {}
可能缺少属性,因此添加了检查。
const obj1={prop1:1,prop2:"foo",prop3:{prop4:2,prop5:"bar"},prop7:{pro8:"only in 1"}},
obj2={prop1:3,prop2:"foo",prop3:{prop4:2,prop5:"foobar"}, prop6: "only in 2"};
const isObject = val => val && typeof val === 'object'; // required for "null" comparison
function compare(obj1, obj2) {
let equality = {},
merged = { ...obj1, ...obj2 }; // has properties of both
for (let key in merged) {
let value1 = obj1[key], value2 = obj2[key];
if (isObject(value1) || isObject(value2)) {
equality[key] = compare(value1 || {}, value2 || {});
} else {
equality[key] = value1 === value2
}
}
return equality;
}
console.log(compare(obj1, obj2))
答案 2 :(得分:1)
您可以使用reduce
来构建新对象,并可以使用另一种get
方法通过string
从其他对象中获取嵌套道具,并将其与第一个对象中的当前道具值进行比较。
const obj1 = { prop1: 1, prop2: "foo", prop3: { prop4: 2, prop5: "bar" } }
const obj2 = { prop1: 3, prop2: "foo", prop3: { prop4: 2, prop5: "foobar" } }
function get(obj, path) {
return path.split('.').reduce((r, e) => {
if (!r) return r
else return r[e] || undefined
}, obj)
}
function compare(a, b, prev = "") {
return Object.keys(a).reduce((r, e) => {
const path = prev + (prev ? '.' + e : e);
const value = a[e] === get(b, path);
r[e] = typeof a[e] === 'object' ? compare(a[e], b, path) : value
return r;
}, {})
}
const result = compare(obj1, obj2);
console.log(result)
要比较这两个对象的所有属性,您可以创建额外的功能,以执行两个对象的循环。
const obj1 = {"prop1":1,"prop2":"foo","prop3":{"prop4":2,"prop5":"bar"},"prop7":{"prop9":{"prop10":"foo"}}}
const obj2 = {"prop1":3,"prop2":"foo","prop3":{"prop4":2,"prop5":"foobar"},"prop6":"new","prop7":{"foo":"foo","bar":{"baz":"baz"}}}
function get(obj, path) {
return path.split('.').reduce((r, e) => {
if (!r) return r;
else return r[e] || undefined;
}, obj);
}
function isEmpty(o) {
if (typeof o !== 'object') return true;
else return !Object.keys(o).length;
}
function build(a, b, o = null, prev = '') {
return Object.keys(a).reduce(
(r, e) => {
const path = prev + (prev ? '.' + e : e);
const bObj = get(b, path);
const value = a[e] === bObj;
if (typeof a[e] === 'object') {
if (isEmpty(a[e]) && isEmpty(bObj)) {
if (e in r) r[e] = r[e];
else r[e] = true;
} else if (!bObj && isEmpty(a[e])) {
r[e] = value;
} else {
r[e] = build(a[e], b, r[e], path);
}
} else {
r[e] = value;
}
return r;
},
o ? o : {}
);
}
function compare(a, b) {
const o = build(a, b);
return build(b, a, o);
}
const result = compare(obj1, obj2);
console.log(result)
答案 3 :(得分:1)
一个递归示例,
var obj1 = {
prop1: 1,
prop2: "foo",
prop3: {
prop4: 2,
prop5: "bar"
},
prop7: {},
}
var obj2 = {
prop1: 3,
prop2: "foo",
prop3: {
prop4: 2,
prop5: "foobar"
},
prop6: "new",
prop7: {},
prop8: {},
}
var result = {};
function compare(obj1, obj2, obj_) {
for (let k in obj1) {
var type = typeof obj1[k];
if (type === 'object') {
obj_[k] = {};
if (!obj2[k]){
obj_[k] = false;
}else if ((Object.entries(obj1[k]).length === 0 && obj1[k].constructor === Object) && (Object.entries(obj2[k]).length === 0 && obj2[k].constructor === Object)) {
obj_[k] = true;
} else {
compare(obj1[k], obj2[k], obj_[k]);
}
} else {
obj_[k] = (obj1[k] === obj2[k]);
}
}
}
if (Object.keys(obj1).length < Object.keys(obj2).length) { //check if both objects vary in length.
var tmp = obj1;
obj1 = obj2;
obj2 = tmp;
}
compare(obj1, obj2, result);
console.log(result);
答案 4 :(得分:1)
这是我最近提出的可以解决相同问题的解决方案,它需要一个可选键来设置比较严格性。在后端将值作为数字发送但希望该值作为字符串返回时很有用。我们一直在使用JSON.stringify比较,但是它有点粗糙,无法说明对象何时相同但键的顺序不同。
public objectsAreTheSame(objA: {[key: string]: any}, objB: {[key: string]: any}, isStrict = false): boolean {
let areTheSame = true;
const strictLevel = isStrict ? 'isStrict' : 'isNotStrict';
const valuesDoNotMatch = {
'isStrict': (a, b) => a !== b,
'isNotStrict': (a, b) => a != b
};
const isObject = (a, b) => typeof a === 'object' && !Array.isArray(a) && (!!a && !!b);
const compareArrays = (a, b) => {
if (a.length === b.length) {
a.sort();
b.sort();
a.forEach((ele, idx) => compareValues(ele, b[idx]));
} else {
areTheSame = false;
}
};
const compareValues = (a, b) => {
if (Array.isArray(a)) {
compareArrays(a, b);
} else if (!isObject(a, b) && valuesDoNotMatch[strictLevel](a, b)) {
areTheSame = false;
} else if (isObject(a, b) && !this.objectsAreTheSame(a, b, isStrict)) {
areTheSame = false;
}
};
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) return false;
for (let key of keysA) compareValues(objA[key], objB[key]);
return areTheSame;
}