How to compare two objects in JavaScript
Tags: javascript, tutorial, webdev
Published: 2023-11-19 23:19:57

To begin with, it's essential to understand what an object is in **JavaScript**.

An object is defined by a set of key-value pairs, where keys are known as "_properties_" and values can be any JavaScript data type, including other objects or functions. Here's a simple example of a JavaScript object:

```javascript
const objectExample = {
  name: "John",
  age: 30,
  city: "New York"
}
```

In JavaScript, objects cannot be directly compared using comparison operators like **==** or **===** because these operators check for the equality of values, and objects are actually stored as _references_ in memory, not as actual values. This means that when you compare two objects using these operators, you are comparing their references, not their actual content. You can find a good tutorial on this topic [here](https://www.youtube.com/watch?v=Hci9Bb4_fkA)

For example, let's assume we have two objects:

```javascript
const object1 = {
  name: "John",
  age: 30,
  city: "New York"
};

const object2 = {
  name: "John",
  age: 30,
  city: "New York"
};
```
In this scenario, even though these two objects contain the same data, they are stored as separate _references_ in memory. Consequently, the following comparison will return **false**:

```javascript
console.log(object1 === object2); // false
```

---

So, how do we compare two objects in JavaScript?
---
![how-to-compare-two-objects-in-javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oq4l11bhj64iiy398tu6.gif)
---

---

## The first option is to use **JSON.stringify()**.
This method is an efficient way to compare two objects in JavaScript. This method converts an object into a string representation in JSON format. Since JSON is a standardized format and is represented as a string, the comparison becomes much simpler.

Here is an example of how to use it:
```javascript
const object1 = {
  name: "John",
  age: 30,
  city: "New York"
};

const object2 = {
  name: "John",
  age: 30,
  city: "New York"
};

const jsonString1 = JSON.stringify(object1);
const jsonString2 = JSON.stringify(object2);

// jsonString1 
// {"name":"John","age":30,"city":"New York"}

// jsonString2
// {"name":"John","age":30,"city":"New York"}

console.log(jsonString1 === jsonString2 ); // true
```
The **order** of properties or keys does not matter when using the _JSON.stringify()_ method. JSON is a data format that does not preserve the order of keys in objects. Therefore, even if the order of properties is different between objects, the produced JSON strings will be the same, and their comparison will consider the objects as equal.

However, there are some limitations when using _JSON.stringify()_ to convert objects into JSON strings:

- **Functions**
If the object contains functions or methods, they will not be included in the JSON string generated by JSON.stringify(). Functions are not serializable in JSON format and will be ignored.
```javascript
const objectExample = {
  name: "John",
  age: 30,
  city: "New York",
  sayHello: function() {
    console.log("Hello!");
  }
}
```
If you try to apply **JSON.stringify(objectExample)** to this object, the **sayHello** function will be ignored, and the result will only display the serializable properties.

```javascript
// objectExample
// {"name":"John","age":30,"city":"New York"}
```

- **Circular References**
If there are circular references in objects (meaning an object refers to another object, which in turn refers back to the first object), then _JSON.stringify_ will enter an infinite loop and throw an exception. This occurs because JSON format is a linear format, and circular references cannot be directly represented.
To learn more about _circular references_ and what they entail, [here](https://www.freecodecamp.org/news/circular-reference-in-javascript-explained/) is a very informative article.

---

## The second approach is to use **Shallow equality.**
During the shallow equality check of objects, you obtain the list of properties (using **Object.keys()**) of both objects, and then you check the values of these properties for equality.
```javascript
function shallowEquality(object1, object2) {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);

  if (keys1.length !== keys2.length) {
    return false;
  }

  for (let key of keys1) {
    if (object1[key] !== object2[key]) {
      return false;
    }
  }

  return true;
}
```
This function compares two objects for shallow equality. It first retrieves the keys of both objects, checks if the number of keys is the same, and then iterates through the keys to compare the values. If all values are equal, the function returns true; otherwise, it returns false.

---

## The third approach is to use **Deep equality.**
Deep equality shares similarities with shallow equality but introduces a crucial distinction. In the process of comparing objects, when the values under examination are themselves objects, a recursive equality check is executed on these nested objects.

```javascript
function deepEqual(obj1, obj2) {
  // Basic check for shallow equality
  
  for (let key in obj1) {
    // Check if the property exists in both objects
    if (obj1.hasOwnProperty(key) !== obj2.hasOwnProperty(key)) {
      return false;
    } 
    // If the property values are objects, initiate recursive check
    else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
      // Recursive check for embedded objects
      if (!deepEqual(obj1[key], obj2[key])) {
        return false;
      }
    } 
    // Check for equality of non-object property values
    else if (obj1[key] !== obj2[key]) {
      return false;
    }
  }

  // Additional check for exclusive properties of obj2
  for (let key in obj2) {
    // Check if the property exists only in obj2
    if (obj1.hasOwnProperty(key) !== obj2.hasOwnProperty(key)) {
      return false;
    }
  }

  // If all checks pass, the objects are deeply equal
  return true;
}
```
**Recursive Check for Embedded Objects**
If, during the basic check, it is determined that the values being compared are themselves objects, a recursive check is initiated. This process repeats for each embedded object, enabling a deep comparison of all levels of objects.

By applying this recursive approach, deep equality thoroughly explores the structure of objects, ensuring that no detail is overlooked in the comparison process.
```javascript
const object1 = {
  name: "John",
  age: 30,
  adress: {
    city: "New York"
  }
};

const object2 = {
  name: "John",
  age: 30,
  adress: {
    city: "New York"
  }
};

console.log(deepEqual(object1, object2)); // => true
```

---

## The fourth approach is to use **_.isEqual()** from [_Lodash_](https://lodash.com/)
Lodash is a popular JavaScript utility library that provides a variety of helpful functions, and one of them is **_.isEqual()**. This function is designed to perform a deep comparison between two values, checking if they are equivalent in a comprehensive manner.
```javascript
const _ = require('lodash');

const object1 = {
  name: "John",
  age: 30,
  address: {
    city: "New York"
  }
};

const object2 = {
  name: "John",
  age: 30,
  address: {
    city: "New York"
  }
};

if (_.isEqual(object1, object2)) {
  console.log('The objects are deeply equal.');
} else {
  console.log('The objects are not deeply equal.');
}
```

---

## Conclusion
In conclusion, understanding how to compare objects in JavaScript is crucial due to their unique nature as collections of key-value pairs. Traditional comparison operators like == or === fall short when dealing with objects, as they compare references rather than content.

**JSON.stringify() - A Simple Yet Effective Option**
One method for object comparison is using JSON.stringify(). By converting objects to JSON strings, the comparison becomes straightforward. However, it has limitations, such as ignoring functions and struggling with circular references.

**Shallow Equality - A Surface-Level Check**
Shallow equality involves comparing the values of properties at the top level. It uses Object.keys() to retrieve property lists and checks their values for equality. This approach provides a basic comparison but is limited to the object's first layer.

**Deep Equality - Uncovering Hidden Depths**
Deep equality takes the comparison a step further. When encountering nested objects, it initiates a recursive check, ensuring a thorough examination of all levels. This method provides a comprehensive solution, covering not only the surface but also the inner depths of objects.

**Lodash's _.isEqual() - A Trusted Ally**
For a robust and widely used solution, Lodash's _.isEqual() comes into play. This utility library function performs a deep comparison, offering a reliable and efficient method to ascertain the equivalence of two objects.

In choosing the right method, consider the complexity of your objects and the depth of the comparison needed. Each approach has its strengths and limitations, so selecting the most suitable one depends on the specific requirements of your JavaScript application.