Four ways to compare JavaScript objects

Four ways to compare JavaScript objects

Preface

Comparing primitive values ​​in JavaScript is very simple. Just use any of the available equality operators, such as the strict equality operator:

'a' === 'c'; // => false
1 === 1; // => true

Objects, however, have structured data, so comparison is more difficult. In this article, you will learn how to properly compare objects in JavaScript.

Reference Comparison

JavaScript provides three methods for comparing values:

  • Strict equality operator ===
  • Loose equality operator ==
  • Object.is() Function

When objects are compared using any of the above methods, the comparison evaluates to true only if the compared values ​​refer to the same object instance. This is reference equality .

Let's define objects hero1 and hero2 and see referential equality in action:

const hero1 = {
  name: 'Batman'
};
const hero2 = {
  name: 'Batman'
};

hero1 === hero1; // => true
hero1 === hero2; // => false

hero1 == hero1; // => true
hero1 == hero2; // => false

Object.is(hero1, hero1); // => true
Object.is(hero1, hero2); // => false

hero1 === hero1 evaluates to true because both operands refer to the same object instance, hero1.

On the other hand, hero1 === hero2 evaluates to false because hero1 and hero2 are different object instances.

Interestingly, the contents of the hero1 and hero2 objects are identical: both objects have a name property whose value is 'Batman'. However, hero1 === hero2 evaluates to false even when comparing objects of the same structure.

Reference equality is useful when you want to compare object references rather than their contents. But in more cases, you want to compare the actual contents of objects: ie properties and their values.

Next, let's see how to compare objects based on their contents.

Manual comparison

The most straightforward way to compare objects by content is to read the properties and compare them manually.

For example, let's write a special function isHeroEqual() to compare two hero objects:

function isHeroEqual(object1, object2) {
  return object1.name === object2.name;
}

const hero1 = {
  name: 'Batman'
};
const hero2 = {
  name: 'Batman'
};
const hero3 = {
  name: 'Joker'
};

isHeroEqual(hero1, hero2); // => true
isHeroEqual(hero1, hero3); // => false

isHeroEqual() accesses the name property of both objects and compares their values.

If the objects being compared have some properties, I prefer to write a comparison function like isHeroEqual(). This type of function has good performance: only a few property accessors and equality operators are involved in the comparison.

Manual comparison requires manual extraction of properties, which is not a problem for simple objects. However, for comparing larger objects (or objects with unknown structure), it is not convenient because it requires a lot of boilerplate code.

So let's see how shallow comparison of objects can help.

Shallow comparison

If you check objects using shallow comparison, you must get a list of the properties of both objects (using Object.keys()) and then check whether their property values ​​are equal.

The following code is an implementation of shallow comparison:

function shallowEqual(object1, object2) {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);

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

  for (let index = 0; index < keys1.length; index++) {
    const val1 = object1[keys1[index]];
    const val2 = object2[keys2[index]];
    if (val1 !== val2) {
      return false;
    }
  }

  return true;
}

Inside the function, keys1 and keys2 are arrays containing the names of the properties of object1 and object2 respectively.

Iterate over the keys with a for loop and compare each property of object1 and object2.

Using shallow comparison, you can easily check equality on objects with many properties:

const hero1 = {
  name: 'Batman',
  realName: 'Bruce Wayne'
};
const hero2 = {
  name: 'Batman',
  realName: 'Bruce Wayne'
};
const hero3 = {
  name: 'Joker'
};

shallowEqual(hero1, hero2); // => true
shallowEqual(hero1, hero3); // => false

shallowEqual(hero1, hero2) returns true because objects hero1 and hero2 have

Same attributes (name and realName), and the values ​​are also the same.

On the other hand, since hero1 and hero3 have different properties, shallowEqual(hero1, hero3) will return false.

But objects in JavaScript can be nested. Shallow comparison doesn't work well in this case.

The following performs a shallow comparison check on an object with nested objects:

const hero1 = {
  name: 'Batman',
  address:
    city: 'Gotham'
  }
};
const hero2 = {
  name: 'Batman',
  address:
    city: 'Gotham'
  }
};

shallowEqual(hero1, hero2); // => false

This time, even though the two objects hero1 and hero2 have the same content, shallowEqual(hero1, hero2) will return false.

This happens because the nested objects hero1.address and hero2.address are different object instances. Therefore, the shallow comparison considers hero1.address and hero2.address to be two different values.

Solving the problem of nested objects requires deep comparison.

Deep Comparison

Deep comparison is similar to shallow comparison, except that when properties contain objects, a recursive shallow comparison is performed on the nested objects.

Take a look at the implementation of deep comparison:

function deepEqual(object1, object2) {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);

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

  for (let index = 0; index < keys1.length; index++) {
    const val1 = object1[keys1[index]];
    const val2 = object2[keys2[index]];
    const areObjects = isObject(val1) && isObject(val2);
    if (areObjects && !deepEqual(val1, val2) || 
        !areObjects && val1 !== val2) {
      return false;
    }
  }

  return true;
}

function isObject(object) {
  return object != null && typeof object === 'object';
}

Line 13 areObjects && !deepEqual(val1, val2) Once the property checked is an object, the recursive call will start to verify whether the nested objects are also equal.

Now let's compare objects with nested objects using deepEquality():

const hero1 = {
  name: 'Batman',
  address:
    city: 'Gotham'
  }
};
const hero2 = {
  name: 'Batman',
  address:
    city: 'Gotham'
  }
};

deepEqual(hero1, hero2); // => true

The deep comparison function correctly determines whether hero1 and hero2 have the same properties and values, including the equality of the nested objects hero1.address and hero2.address.

For deep comparison of objects, I recommend using isDeepStrictEqual(object1, object2) from Node's built-in util module or _.isEqual(object1, object2) from the lodash library.

Summarize

Reference equality (using ===, ==, or Object.is()) is used to determine whether the operands are the same object instance.

Manually checking for object equality requires manual comparison of property values. Although this type of check requires manual coding to compare the attributes, it is convenient because it is simple.

A better approach is to use shallow checking when the objects being compared have many properties or when the structure of the objects is determined at runtime.

If the objects being compared have nested objects, a deep comparison check should be performed.

The above are the details of the four ways to compare JavaScript objects. For more information about JavaScript, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • An example of how to compare two objects in js
  • js compares two separate arrays or objects for equality
  • How to compare two Json objects in JS for equality? Example code
  • Detailed explanation of JS example of comparing the values ​​of two Json objects to see if they are equal
  • Comparison of js objects
  • JavaScript object comparison implementation code
  • Detailed explanation of four methods of JavaScript objects

<<:  How to simulate enumeration with JS

>>:  Storage engine and log description based on MySQL (comprehensive explanation)

Recommend

JavaScript offsetParent case study

1. Definition of offsetParent: offsetParent is th...

Steps to install Pyenv under Deepin

Preface In the past, I always switched Python ver...

A general method for implementing infinite text carousel with native CSS

Text carousels are very common in our daily life....

Example of converting webpack images to base64

Download url-loader yarn add -D url-loader module...

Example of Html shielding right-click menu and left-click typing function

Disable right-click menu <body oncontextmenu=s...

How to avoid the trap of URL time zone in MySQL

Preface Recently, when using MySQL 6.0.x or highe...

Detailed explanation of rpm installation in mysql

View installation and uninstallation # View rpm -...

Detailed introduction to CSS priority knowledge

Before talking about CSS priority, we need to und...

JavaScript implements page scrolling animation

Table of contents Create a layout Add CSS styles ...

Detailed process of implementing the 2048 mini game in WeChat applet

Rendering Example Code Today we are going to use ...

Markup validation for doctype

But recently I found that using this method will c...

Mini Program to Implement Simple List Function

This article example shares the specific code of ...