对象比较的唯一内置操作是 ==/=== 相等运算符,它使用引用相等:A 是 B,而不是 A 等于 B。
您需要的是描述两个对象之间差异的更改描述符列表。
正如 cmets 中所确定的,这将需要使用引用和存在检查的混合来递归遍历对象。
以下算法是一个想法的快速实现。遍历对象并使用对象列表描述它们的更改。就像对象本身一样,更改是嵌套的,但根据它们在对象中的位置(因此可以展平)具有唯一的 id。
function diff(a, b, namespace) {
namespace = (namespace || '') + '.';
var keysInA = Object.keys(a),
keysInB = Object.keys(b);
var diffA = keysInA.reduce(function(changes, key) {
var ns = namespace + key;
if(typeof b[key] == 'undefined') {
return changes.concat([{ type: 'DELETED', id: ns }]);
}
if(a[key] !== b[key]) {
return changes.concat([{ type: 'CHANGED', id: ns }]);
}
if(typeof a[key] == b[key] == 'object') {
return diff(a[key], b[key], ns);
}
return changes;
}, []);
var diffB = keysInB.reduce(function(changes, key) {
var ns = namespace + key;
if(typeof a[key] == 'undefined') {
return changes.concat([{ type: 'ADDED', id: ns }]);
}
return changes;
}, []);
return diffA.concat(diffB);
}
例如我们取一个对象的原始状态。
var a = { a: 1, b: 2, c: 3 };
还有新的状态。
var b = { a: 2, c: 3, d: 5 };
然后使用diff 函数运行它们。
diff(a, b);
它返回一个更改列表。
[
{ id: '.a', type: 'CHANGED' },
{ id: '.b', type: 'DELETED' },
{ id: '.d', type: 'ADDED' }
]
显然,您必须调整此算法,以使其符合您对构成更改的标准。您可能想查看deep equality,而不是从头到尾比较参考。