Deep equality in JavaScript objects

Compare data in Javascript is always a task that involves some more concern than other languages. The reasons are wide, but generally is related to JS be weak-typed.

One of many JS weirdness

A way to avoid the problem above is use the strict equality operator that considers the type of the data you are trying to compare to assert the equality. But the problem continues if you need to do something a little bit more complex.

Comparing objects

{ name: ‘Raphael’ } == { name: ‘Raphael’ }
// false
{ name: ‘Raphael’ } === { name: ‘Raphael’ }
// false
let myObj = { name: ‘Raphael’ }
myObj == { name: ‘Raphael’ }
// false
myObj === { name: ‘Raphael’ }
// false

But if you compare the current instance of the object, the result is different:

let myObj = { name: ‘Raphael’ }
myObj == myObj
// true
let mySecondObj = myObj // This sets to mySecondObj the same memory address that myObj
mySecondObj == myObj
// true
let myThirdObj = { name: ‘Raphael’ }
myObj == myThirdObj
// false
myObj.name += ‘ Martin’ // Changing myObj, and also mySecondObj
console.log(mySecondObj) // Printing mySecondObj
// {name: "Raphael Martin"}

So, what can you do when you need to check if two different objects have the same properties with the same values? Well, I am sure that there is some npm package just to solve this, or some lodash function that does exactly what you want to do, but I judged that would be nice to create my own.

Creating a function to compare objects

/**
*
*
@param a Object
*
@param b Object
*
@returns {boolean}
*/
function isEqualObjects (a, b) {
for (const key in a) { // Using for-in in a object you can iterate the properties
const a_value = a[key]
const b_value = b[key]
if (a_value !== b_value) {
return false
}
}
return true
}
isEqualObjects(myObj, myThirdObj)
// true

This simple generic function solves most of the problems in development, and in my opinion it is a better approach than put a new JS library in your package.json, which would require to assure that it is in correct version, still available, receiving commits, respecting secure standards, etc. But this solution has a problem: it doesn't make a deep comparison.

let first = {name: ‘L. Hamilton’, car: {team: ‘Mercedes’, tyre: ‘soft’}}
let second = {name: ‘L. Hamilton’, car: {team: ‘Mercedes’, tyre: ‘soft’}}
isEqualObjects(first, second)
// false

It occurs because when setting the 'car' property of the object with an object value, in fact we are instantiating a new object, creating a new pointer. And when the iteration is in the 'car' property it compares two different instances of an object with the operator !==, that always will be truly. How can we solve this? Recursion!

The beauty of a recursion algorithm

So the approach is simple. We are writing a function that checks if objects are equal. If the property of the two objects is also an object, we use the current function to check their properties inequality, else we use the !== operator. The final code is something like this:

/**
*
*
@param a Object
*
@param b Object
*
@returns {boolean}
*/
function isEqualObjects (a, b) {
// if the number of keys is different, they are different
if (Object.keys(a).length !== Object.keys(b).length) {
return false
}

for (const key in a) {
const a_value = a[key]
const b_value = b[key]
// If the value is an object, check if they're different objects
// If it isn't, uses !== to check
if ((a_value instanceof Object && !isEqualObjects(a_value, b_value)) || (!(a_value instanceof Object) && a_value !== b_value)) {
return false
}
}
return true
}

Now, we can deeply compare the objects:

let first = {
"name": "L. Hamilton",
"car": {
"team": "Mercedes",
"tyre": "soft",
"specs": {
"weight": 733,
"liters": 1.6,
"power": 1000
}
}
}
let second = {
"name": "L. Hamilton",
"car": {
"team": "Mercedes",
"tyre": "soft",
"specs": {
"weight": 733,
"liters": 1.6,
"power": 1000
}
}
}
isEqualObjects(first, second)
// true

If you have any suggestions, comment below!

Desenvolvedor Web e Mobile. Falando sobre coisas legais

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store