How to compare two objects in JavaScript?

There is no silver bullet rule to compare the equality of two objects in JavaScript. The proper implementation of the .equals method in any language is trivial. Even in Java, object equality is a big topic.

It is recommended not to try writing your own object equality method instead use any standard library method. These library methods will work in most cases.

Object equality using Lodash

If the project has Lodash please use give Lodash a try. It has a number of useful util functions. For object equality we can use isEqual().

const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', status: null, age: 23};
_.isEqual(obj1, obj2); // true

It will brute force check each key value using ECMAScript 5 in the browser.

Object equality using Angular

In AngularJS, the angular.equals function will checks the equality of two objects. In Ember.js use isEqual.

const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', status: null, age: 23};

angular.equals(obj1, obj2)  // true

Object equality using Ember.js

In Ember.js, isEqual function will check the equality of two objects.

const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', status: null, age: 23};

isEqual(obj1, obj2);   // true

Object equality using custom function

const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', status: null, age: 23};
function deepCompare () {
    var i, l, leftChain, rightChain;

    function compare2Objects (x, y) {
        var p;

        // remember that NaN === NaN returns false
        // and isNaN(undefined) returns true
        if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
            return true;
        }

        // Compare primitives and functions.
        // Check if both arguments link to the same object.
        // Especially useful on the step where we compare prototypes
        if (x === y) {
            return true;
        }

        // Works in case when functions are created in constructor.
        // Comparing dates is a common scenario. Another built-ins?
        // We can even handle functions passed across iframes
        if ((typeof x === 'function' && typeof y === 'function') ||
            (x instanceof Date && y instanceof Date) ||
            (x instanceof RegExp && y instanceof RegExp) ||
            (x instanceof String && y instanceof String) ||
            (x instanceof Number && y instanceof Number)) {
            return x.toString() === y.toString();
        }

        // At last checking prototypes as good as we can
        if (!(x instanceof Object && y instanceof Object)) {
            return false;
        }

        if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
            return false;
        }

        if (x.constructor !== y.constructor) {
            return false;
        }

        if (x.prototype !== y.prototype) {
            return false;
        }

        // Check for infinitive linking loops
        if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
            return false;
        }

        // Quick checking of one object being a subset of another.
        // todo: cache the structure of arguments[0] for performance
        for (p in y) {
            if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
                return false;
            }
            else if (typeof y[p] !== typeof x[p]) {
                return false;
            }
        }

        for (p in x) {
            if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
                return false;
            }
            else if (typeof y[p] !== typeof x[p]) {
                return false;
            }

            switch (typeof (x[p])) {
                case 'object':
                case 'function':

                    leftChain.push(x);
                    rightChain.push(y);

                    if (!compare2Objects (x[p], y[p])) {
                        return false;
                    }

                    leftChain.pop();
                    rightChain.pop();
                    break;

                default:
                    if (x[p] !== y[p]) {
                        return false;
                    }
                    break;
            }
        }

        return true;
    }

    if (arguments.length < 1) {
        return true;
        // Die silently? Don't know how to handle such case, please help...
        // throw "Need two or more arguments to compare";
    }

    for (i = 1, l = arguments.length; i < l; i++) {

        leftChain = []; //Todo: this can be cached
        rightChain = [];

        if (!compare2Objects(arguments[0], arguments[i])) {
            return false;
        }
    }

    return true;
}

console.log(deepCompare(obj1, obj2)); // true

Object equality using JSON.stringify

When we have basic JSON-style objects and does not have methods and DOM nodes inside the object, we can use this quick and dirty approach:

JSON.stringify does not work for objects with circular references
const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', age: 23, status: null};

JSON.stringify(obj1) === JSON.stringify(obj2) // true

When we are using JSON.stringify the order of the object properties is vital. For the following objects it will return false. 
const obj1 = {name: 'Joe Smith', age: 23, status: null};
const obj2 = {name: 'Joe Smith', status: null, age: 23};

JSON.stringify(obj1) === JSON.stringify(obj2) // false
Reference: