The only built in operation for object comparison is the ==
/===
equality operators, which use reference equality: A is B, rather than A is equal to B.
What you want is a list of change descriptors describing the difference between two objects.
As identified in the comments, this is going to need a recursive traversal of the objects, using a mixture of reference and existence checks.
The following algorithm is a quick implementation of an idea. The objects are traversed and their changes are described with a list of objects. Just like the objects themselves, the changes are nested, but have a unique id, based on their location within the object (so it could be flattened).
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);
}
For example we take the original state of an object.
var a = { a: 1, b: 2, c: 3 };
And the new state.
var b = { a: 2, c: 3, d: 5 };
Then run them with the diff
function.
diff(a, b);
It returns a list of the changes.
[
{ id: '.a', type: 'CHANGED' },
{ id: '.b', type: 'DELETED' },
{ id: '.d', type: 'ADDED' }
]
Obviously, you would have to adapt this algorithm to make it fit your criteria for what constitutes a change. You might want to look at deep equality, rather than comparing references the whole way down.