EN
JavaScript - deep compare of two objects
6
points
In this article we are going to look how to compare two objects in JavaScript. By default JavaScript provides ==
and ===
operators. But thay are not enought to compare complex objects because they compares only references for them. To solve this problem it is necessary to attach external library or write custom function.
Below simple custom implementation for equals
method is presented.
1. Deep compare objects method example
Presented solution in this section uses recursion to compare properties.
// ONLINE-RUNNER:browser;
function equals(a, b) {
if (a === b) {
return true;
}
if ((a instanceof Object) && (b instanceof Object)) {
if (a.constructor !== b.constructor) {
return false;
}
for (const key in a) {
if (a.hasOwnProperty(key)) {
if (!b.hasOwnProperty(key) || !equals(a[key], b[key])) {
return false;
}
}
}
for (const key in b) {
if (b.hasOwnProperty(key) && !a.hasOwnProperty(key)) {
return false;
}
}
return true;
}
return false;
}
// Usage example:
var object1 = {
name: 'John',
items: [1, 2, '3', {name: 'Item'}]
};
var object2 = {
name: 'John',
items: [1, 2, '3', {name: 'Item 2'}]
};
var array1 = [1, 2, 3];
var array2 = [1, 2, '3'];
console.log( equals( 1, 1 ) ); // true
console.log( equals( 'abc', 'abc' ) ); // true
console.log( equals( null, null ) ); // true
console.log( equals( true, false ) ); // false
console.log( equals( 123, '123' ) ); // false
console.log( equals( object1, object1 ) ); // true
console.log( equals( object1, object2 ) ); // false
console.log( equals( array1, array1 ) ); // true
console.log( equals( array1, array2 ) ); // false
2. Deep compare objects method with printing difference example
In this section extended equals
method that logs difference between objects is presented.
// ONLINE-RUNNER:browser;
function compare(a, b) {
var logs = [];
function log(log, path) {
if (path) {
logs.push(log + ' (path: ' + path + ').');
} else {
logs.push(log + '.');
}
}
function analyse(a, b, path) {
if (a === b) {
return;
}
if ((a instanceof Object) && (b instanceof Object)) {
if (a.constructor !== b.constructor) {
log('Entities do not have same constructors', path);
return;
}
for (const key in a) {
if (a.hasOwnProperty(key)) {
if (!b.hasOwnProperty(key)) {
log('Property "' + key + '" does not exist in first entity', path);
continue;
}
analyse(a[key], b[key], path ? path + ' -> ' + key: key) ;
}
}
for (const key in b) {
if (b.hasOwnProperty(key) && !a.hasOwnProperty(key)) {
log('Property "' + key + '" does not exist in second entity', path);
}
}
} else {
log('Entities are not equal', path);
}
}
analyse(a, b, '');
return logs;
}
// Usage example:
var object1 = {
name: 'John',
items: [1, 2, '3', {name: 'Item', z: [4]}]
};
var object2 = {
name: 'John',
items: ['1', 2, 3, {name: 'Item 2', x: 3}]
};
var logs = compare(object1, object2);
if (logs.length == 0) {
console.log('Objects are equal.');
} else {
console.log('Objects differ in:');
for (var i = 0; i < logs.length; ++i) {
console.log(' ' + logs[i]);
}
}