[javascript] How to determine equality for two JavaScript objects?

A strict equality operator will tell you if two object types are equal. However, is there a way to tell if two objects are equal, much like the hash code value in Java?

Stack Overflow question Is there any kind of hashCode function in JavaScript? is similar to this question, but requires a more academic answer. The scenario above demonstrates why it would be necessary to have one, and I'm wondering if there is any equivalent solution.

This question is related to javascript object equals hashcode

The answer is


The short answer

The simple answer is: No, there is no generic means to determine that an object is equal to another in the sense you mean. The exception is when you are strictly thinking of an object being typeless.

The long answer

The concept is that of an Equals method that compares two different instances of an object to indicate whether they are equal at a value level. However, it is up to the specific type to define how an Equals method should be implemented. An iterative comparison of attributes that have primitive values may not be enough, there may well be attributes which are not to be considered part of the object value. For example,

 function MyClass(a, b)
 {
     var c;
     this.getCLazy = function() {
         if (c === undefined) c = a * b // imagine * is really expensive
         return c;
     }
  }

In this above case, c is not really important to determine whether any two instances of MyClass are equal, only a and b are important. In some cases c might vary between instances and yet not be significant during comparison.

Note this issue applies when members may themselves also be instances of a type and these each would all be required to have a means of determining equality.

Further complicating things is that in JavaScript the distinction between data and method is blurred.

An object may reference a method that is to be called as an event handler, and this would likely not be considered part of its 'value state'. Whereas another object may well be assigned a function that performs an important calculation and thereby makes this instance different from others simply because it references a different function.

What about an object that has one of its existing prototype methods overridden by another function? Could it still be considered equal to another instance that it otherwise identical? That question can only be answered in each specific case for each type.

As stated earlier, the exception would be a strictly typeless object. In which case the only sensible choice is an iterative and recursive comparison of each member. Even then one has to ask what is the 'value' of a function?


It's useful to consider two objects equal if they have all the same values for all properties and recursively for all nested objects and arrays. I also consider the following two objects equal:

var a = {p1: 1};
var b = {p1: 1, p2: undefined};

Similarly, arrays can have "missing" elements and undefined elements. I would treat those the same as well:

var c = [1, 2];
var d = [1, 2, undefined];

A function that implements this definition of equality:

function isEqual(a, b) {
    if (a === b) {
        return true;
    }

    if (generalType(a) != generalType(b)) {
        return false;
    }

    if (a == b) {
        return true;
    }

    if (typeof a != 'object') {
        return false;
    }

    // null != {}
    if (a instanceof Object != b instanceof Object) {
        return false;
    }

    if (a instanceof Date || b instanceof Date) {
        if (a instanceof Date != b instanceof Date ||
            a.getTime() != b.getTime()) {
            return false;
        }
    }

    var allKeys = [].concat(keys(a), keys(b));
    uniqueArray(allKeys);

    for (var i = 0; i < allKeys.length; i++) {
        var prop = allKeys[i];
        if (!isEqual(a[prop], b[prop])) {
            return false;
        }
    }
    return true;
}

Source code (including the helper functions, generalType and uniqueArray): Unit Test and Test Runner here.


Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).


I use this comparable function to produce copies of my objects that are JSON comparable:

_x000D_
_x000D_
var comparable = o => (typeof o != 'object' || !o)? o :_x000D_
  Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});_x000D_
_x000D_
// Demo:_x000D_
_x000D_
var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };_x000D_
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };_x000D_
_x000D_
console.log(JSON.stringify(comparable(a)));_x000D_
console.log(JSON.stringify(comparable(b)));_x000D_
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));
_x000D_
<div id="div"></div>
_x000D_
_x000D_
_x000D_

Comes in handy in tests (most test frameworks have an is function). E.g.

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

If a difference is caught, strings get logged, making differences spottable:

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

This is my version. It is using new Object.keys feature that is introduced in ES5 and ideas/tests from +, + and +:

_x000D_
_x000D_
function objectEquals(x, y) {_x000D_
    'use strict';_x000D_
_x000D_
    if (x === null || x === undefined || y === null || y === undefined) { return x === y; }_x000D_
    // after this just checking type of one would be enough_x000D_
    if (x.constructor !== y.constructor) { return false; }_x000D_
    // if they are functions, they should exactly refer to same one (because of closures)_x000D_
    if (x instanceof Function) { return x === y; }_x000D_
    // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)_x000D_
    if (x instanceof RegExp) { return x === y; }_x000D_
    if (x === y || x.valueOf() === y.valueOf()) { return true; }_x000D_
    if (Array.isArray(x) && x.length !== y.length) { return false; }_x000D_
_x000D_
    // if they are dates, they must had equal valueOf_x000D_
    if (x instanceof Date) { return false; }_x000D_
_x000D_
    // if they are strictly equal, they both need to be object at least_x000D_
    if (!(x instanceof Object)) { return false; }_x000D_
    if (!(y instanceof Object)) { return false; }_x000D_
_x000D_
    // recursive object equality check_x000D_
    var p = Object.keys(x);_x000D_
    return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) &&_x000D_
        p.every(function (i) { return objectEquals(x[i], y[i]); });_x000D_
}_x000D_
_x000D_
_x000D_
///////////////////////////////////////////////////////////////_x000D_
/// The borrowed tests, run them by clicking "Run code snippet"_x000D_
///////////////////////////////////////////////////////////////_x000D_
var printResult = function (x) {_x000D_
    if (x) { document.write('<div style="color: green;">Passed</div>'); }_x000D_
    else { document.write('<div style="color: red;">Failed</div>'); }_x000D_
};_x000D_
var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } }_x000D_
assert.isTrue(objectEquals(null,null));_x000D_
assert.isFalse(objectEquals(null,undefined));_x000D_
assert.isFalse(objectEquals(/abc/, /abc/));_x000D_
assert.isFalse(objectEquals(/abc/, /123/));_x000D_
var r = /abc/;_x000D_
assert.isTrue(objectEquals(r, r));_x000D_
_x000D_
assert.isTrue(objectEquals("hi","hi"));_x000D_
assert.isTrue(objectEquals(5,5));_x000D_
assert.isFalse(objectEquals(5,10));_x000D_
_x000D_
assert.isTrue(objectEquals([],[]));_x000D_
assert.isTrue(objectEquals([1,2],[1,2]));_x000D_
assert.isFalse(objectEquals([1,2],[2,1]));_x000D_
assert.isFalse(objectEquals([1,2],[1,2,3]));_x000D_
_x000D_
assert.isTrue(objectEquals({},{}));_x000D_
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));_x000D_
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));_x000D_
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));_x000D_
_x000D_
assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));_x000D_
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));_x000D_
_x000D_
Object.prototype.equals = function (obj) { return objectEquals(this, obj); };_x000D_
var assertFalse = assert.isFalse,_x000D_
    assertTrue = assert.isTrue;_x000D_
_x000D_
assertFalse({}.equals(null));_x000D_
assertFalse({}.equals(undefined));_x000D_
_x000D_
assertTrue("hi".equals("hi"));_x000D_
assertTrue(new Number(5).equals(5));_x000D_
assertFalse(new Number(5).equals(10));_x000D_
assertFalse(new Number(1).equals("1"));_x000D_
_x000D_
assertTrue([].equals([]));_x000D_
assertTrue([1,2].equals([1,2]));_x000D_
assertFalse([1,2].equals([2,1]));_x000D_
assertFalse([1,2].equals([1,2,3]));_x000D_
assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));_x000D_
assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));_x000D_
_x000D_
assertTrue({}.equals({}));_x000D_
assertTrue({a:1,b:2}.equals({a:1,b:2}));_x000D_
assertTrue({a:1,b:2}.equals({b:2,a:1}));_x000D_
assertFalse({a:1,b:2}.equals({a:1,b:3}));_x000D_
_x000D_
assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));_x000D_
assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));_x000D_
_x000D_
var a = {a: 'text', b:[0,1]};_x000D_
var b = {a: 'text', b:[0,1]};_x000D_
var c = {a: 'text', b: 0};_x000D_
var d = {a: 'text', b: false};_x000D_
var e = {a: 'text', b:[1,0]};_x000D_
var i = {_x000D_
    a: 'text',_x000D_
    c: {_x000D_
        b: [1, 0]_x000D_
    }_x000D_
};_x000D_
var j = {_x000D_
    a: 'text',_x000D_
    c: {_x000D_
        b: [1, 0]_x000D_
    }_x000D_
};_x000D_
var k = {a: 'text', b: null};_x000D_
var l = {a: 'text', b: undefined};_x000D_
_x000D_
assertTrue(a.equals(b));_x000D_
assertFalse(a.equals(c));_x000D_
assertFalse(c.equals(d));_x000D_
assertFalse(a.equals(e));_x000D_
assertTrue(i.equals(j));_x000D_
assertFalse(d.equals(k));_x000D_
assertFalse(k.equals(l));_x000D_
_x000D_
// from comments on stackoverflow post_x000D_
assert.isFalse(objectEquals([1, 2, undefined], [1, 2]));_x000D_
assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }));_x000D_
assert.isFalse(objectEquals(new Date(1234), 1234));_x000D_
_x000D_
// no two different function is equal really, they capture their context variables_x000D_
// so even if they have same toString(), they won't have same functionality_x000D_
var func = function (x) { return true; };_x000D_
var func2 = function (x) { return true; };_x000D_
assert.isTrue(objectEquals(func, func));_x000D_
assert.isFalse(objectEquals(func, func2));_x000D_
assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } }));_x000D_
assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));
_x000D_
_x000D_
_x000D_


Needing a more generic object comparison function than had been posted, I cooked up the following. Critique appreciated...

Object.prototype.equals = function(iObj) {
  if (this.constructor !== iObj.constructor)
    return false;
  var aMemberCount = 0;
  for (var a in this) {
    if (!this.hasOwnProperty(a))
      continue;
    if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
      return false;
    ++aMemberCount;
  }
  for (var a in iObj)
    if (iObj.hasOwnProperty(a))
      --aMemberCount;
  return aMemberCount ? false : true;
}

Sure, while we're at it I'll throw in my own reinvention of the wheel (I'm proud of the number of spokes and materials used):

////////////////////////////////////////////////////////////////////////////////

var equals = function ( objectA, objectB ) {
    var result = false,
        keysA,
        keysB;

    // Check if they are pointing at the same variable. If they are, no need to test further.
    if ( objectA === objectB ) {
        return true;
    }

    // Check if they are the same type. If they are not, no need to test further.
    if ( typeof objectA !== typeof objectB ) {
        return false;
    }

    // Check what kind of variables they are to see what sort of comparison we should make.
    if ( typeof objectA === "object" ) {
        // Check if they have the same constructor, so that we are comparing apples with apples.
        if ( objectA.constructor === objectA.constructor ) {
            // If we are working with Arrays...
            if ( objectA instanceof Array ) {
                // Check the arrays are the same length. If not, they cannot be the same.
                if ( objectA.length === objectB.length ) {
                    // Compare each element. They must be identical. If not, the comparison stops immediately and returns false.
                    return objectA.every(
                        function ( element, i ) {
                            return equals( element, objectB[ i ] );
                        }
                    );
                }
                // They are not the same length, and so are not identical.
                else {
                    return false;
                }
            }
            // If we are working with RegExps...
            else if ( objectA instanceof RegExp ) {
                // Return the results of a string comparison of the expression.
                return ( objectA.toString() === objectB.toString() );
            }
            // Else we are working with other types of objects...
            else {
                // Get the keys as arrays from both objects. This uses Object.keys, so no old browsers here.
                keysA = Object.keys( objectA );

                keysB = Object.keys( objectB );

                // Check the key arrays are the same length. If not, they cannot be the same.
                if ( keysA.length === keysB.length ) {
                    // Compare each property. They must be identical. If not, the comparison stops immediately and returns false.
                    return keysA.every(
                        function ( element ) {
                            return equals( objectA[ element ], objectB[ element ] );
                        }
                    );
                }
                // They do not have the same number of keys, and so are not identical.
                else {
                    return false;
                }
            }
        }
        // They don't have the same constructor.
        else {
            return false;
        }
    }
    // If they are both functions, let us do a string comparison.
    else if ( typeof objectA === "function" ) {
        return ( objectA.toString() === objectB.toString() );
    }
    // If a simple variable type, compare directly without coercion.
    else {
        return ( objectA === objectB );
    }

    // Return a default if nothing has already been returned.
    return result;
};

////////////////////////////////////////////////////////////////////////////////

It returns false as quickly as possible, but of course for a large object where the difference is deeply nested it could be less effective. In my own scenario, good handling of nested arrays is important.

Hope it helps someone needing this kind of 'wheel'.


var object1 = {name: "humza" , gender : "male", age: 23}
var object2 = {name: "humza" , gender : "male", age: 23}
var result = Object.keys(object1).every((key) =>  object1[key] === object2[key])

Result will be true if object1 has same values on object2.


For those of you using Node, there is a convenient method called isDeepStrictEqual on the nativeutil library that can achieve this.

const util = require('util');

const obj1 = {
  foo: "bar",
  baz: [1, 2]
};

const obj2 = {
  foo: "bar",
  baz: [1, 2]
};


obj1 == obj2 // false
util.isDeepStrictEqual(obj1, obj2) // true

https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2


I see spaghetti code answers. Without using any third party libs, this is very easy.

Firstly sort the two objects by key their key names.

let objectOne = { hey, you }
let objectTwo = { you, hey }

// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
    return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}

let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)

Then simply use a string to compare them.

JSON.stringify(objectOne) === JSON.stringify(objectTwo)

This is a classic javascript question! I created a method to check deep object equality with the feature of being able to select properties to ignore from comparison. Arguments are the two objects to compare, plus, an optional array of stringified property-to-ignore relative path.

function isObjectEqual( o1, o2, ignorePropsArr=[]) {
    // Deep Clone objects
    let _obj1 = JSON.parse(JSON.stringify(o1)),
        _obj2 = JSON.parse(JSON.stringify(o2));
    // Remove props to ignore
    ignorePropsArr.map( p => { 
        eval('_obj1.'+p+' = _obj2.'+p+' = "IGNORED"');
    });
    // compare as strings
    let s1 = JSON.stringify(_obj1),
        s2 = JSON.stringify(_obj2);
    // return [s1==s2,s1,s2];
    return s1==s2;
}

// Objects 0 and 1 are exact equals
obj0 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj1 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj2 = { price: 66544.12, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj3 = { price: 66544.13, RSIs: [0.000432334, 0.00046531], candles: {A: 541, B: 321, C: 4322}}
obj4 = { price: 66544.14, RSIs: [0.000432334, 0.00046530], candles: {A: 543, B: 321, C: 4322}}

isObjectEqual(obj0,obj1) // true
isObjectEqual(obj0,obj2) // false
isObjectEqual(obj0,obj2,['price']) // true
isObjectEqual(obj0,obj3,['price']) // false
isObjectEqual(obj0,obj3,['price','candles.A']) // true
isObjectEqual(obj0,obj4,['price','RSIs[1]'])   // true

var object1 = {name: "humza" , gender : "male", age: 23}
var object2 = {name: "humza" , gender : "male", age: 23}
var result = Object.keys(object1).every((key) =>  object1[key] === object2[key])

Result will be true if object1 has same values on object2.


This is my version. It is using new Object.keys feature that is introduced in ES5 and ideas/tests from +, + and +:

_x000D_
_x000D_
function objectEquals(x, y) {_x000D_
    'use strict';_x000D_
_x000D_
    if (x === null || x === undefined || y === null || y === undefined) { return x === y; }_x000D_
    // after this just checking type of one would be enough_x000D_
    if (x.constructor !== y.constructor) { return false; }_x000D_
    // if they are functions, they should exactly refer to same one (because of closures)_x000D_
    if (x instanceof Function) { return x === y; }_x000D_
    // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)_x000D_
    if (x instanceof RegExp) { return x === y; }_x000D_
    if (x === y || x.valueOf() === y.valueOf()) { return true; }_x000D_
    if (Array.isArray(x) && x.length !== y.length) { return false; }_x000D_
_x000D_
    // if they are dates, they must had equal valueOf_x000D_
    if (x instanceof Date) { return false; }_x000D_
_x000D_
    // if they are strictly equal, they both need to be object at least_x000D_
    if (!(x instanceof Object)) { return false; }_x000D_
    if (!(y instanceof Object)) { return false; }_x000D_
_x000D_
    // recursive object equality check_x000D_
    var p = Object.keys(x);_x000D_
    return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) &&_x000D_
        p.every(function (i) { return objectEquals(x[i], y[i]); });_x000D_
}_x000D_
_x000D_
_x000D_
///////////////////////////////////////////////////////////////_x000D_
/// The borrowed tests, run them by clicking "Run code snippet"_x000D_
///////////////////////////////////////////////////////////////_x000D_
var printResult = function (x) {_x000D_
    if (x) { document.write('<div style="color: green;">Passed</div>'); }_x000D_
    else { document.write('<div style="color: red;">Failed</div>'); }_x000D_
};_x000D_
var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } }_x000D_
assert.isTrue(objectEquals(null,null));_x000D_
assert.isFalse(objectEquals(null,undefined));_x000D_
assert.isFalse(objectEquals(/abc/, /abc/));_x000D_
assert.isFalse(objectEquals(/abc/, /123/));_x000D_
var r = /abc/;_x000D_
assert.isTrue(objectEquals(r, r));_x000D_
_x000D_
assert.isTrue(objectEquals("hi","hi"));_x000D_
assert.isTrue(objectEquals(5,5));_x000D_
assert.isFalse(objectEquals(5,10));_x000D_
_x000D_
assert.isTrue(objectEquals([],[]));_x000D_
assert.isTrue(objectEquals([1,2],[1,2]));_x000D_
assert.isFalse(objectEquals([1,2],[2,1]));_x000D_
assert.isFalse(objectEquals([1,2],[1,2,3]));_x000D_
_x000D_
assert.isTrue(objectEquals({},{}));_x000D_
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));_x000D_
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));_x000D_
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));_x000D_
_x000D_
assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));_x000D_
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));_x000D_
_x000D_
Object.prototype.equals = function (obj) { return objectEquals(this, obj); };_x000D_
var assertFalse = assert.isFalse,_x000D_
    assertTrue = assert.isTrue;_x000D_
_x000D_
assertFalse({}.equals(null));_x000D_
assertFalse({}.equals(undefined));_x000D_
_x000D_
assertTrue("hi".equals("hi"));_x000D_
assertTrue(new Number(5).equals(5));_x000D_
assertFalse(new Number(5).equals(10));_x000D_
assertFalse(new Number(1).equals("1"));_x000D_
_x000D_
assertTrue([].equals([]));_x000D_
assertTrue([1,2].equals([1,2]));_x000D_
assertFalse([1,2].equals([2,1]));_x000D_
assertFalse([1,2].equals([1,2,3]));_x000D_
assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));_x000D_
assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));_x000D_
_x000D_
assertTrue({}.equals({}));_x000D_
assertTrue({a:1,b:2}.equals({a:1,b:2}));_x000D_
assertTrue({a:1,b:2}.equals({b:2,a:1}));_x000D_
assertFalse({a:1,b:2}.equals({a:1,b:3}));_x000D_
_x000D_
assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));_x000D_
assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));_x000D_
_x000D_
var a = {a: 'text', b:[0,1]};_x000D_
var b = {a: 'text', b:[0,1]};_x000D_
var c = {a: 'text', b: 0};_x000D_
var d = {a: 'text', b: false};_x000D_
var e = {a: 'text', b:[1,0]};_x000D_
var i = {_x000D_
    a: 'text',_x000D_
    c: {_x000D_
        b: [1, 0]_x000D_
    }_x000D_
};_x000D_
var j = {_x000D_
    a: 'text',_x000D_
    c: {_x000D_
        b: [1, 0]_x000D_
    }_x000D_
};_x000D_
var k = {a: 'text', b: null};_x000D_
var l = {a: 'text', b: undefined};_x000D_
_x000D_
assertTrue(a.equals(b));_x000D_
assertFalse(a.equals(c));_x000D_
assertFalse(c.equals(d));_x000D_
assertFalse(a.equals(e));_x000D_
assertTrue(i.equals(j));_x000D_
assertFalse(d.equals(k));_x000D_
assertFalse(k.equals(l));_x000D_
_x000D_
// from comments on stackoverflow post_x000D_
assert.isFalse(objectEquals([1, 2, undefined], [1, 2]));_x000D_
assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }));_x000D_
assert.isFalse(objectEquals(new Date(1234), 1234));_x000D_
_x000D_
// no two different function is equal really, they capture their context variables_x000D_
// so even if they have same toString(), they won't have same functionality_x000D_
var func = function (x) { return true; };_x000D_
var func2 = function (x) { return true; };_x000D_
assert.isTrue(objectEquals(func, func));_x000D_
assert.isFalse(objectEquals(func, func2));_x000D_
assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } }));_x000D_
assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));
_x000D_
_x000D_
_x000D_


One additional option, is use equals of Ramda library:

const c = {a: 1, b: 2};
const d = {b: 2, a: 1};
R.equals(c, d); //=> true

Short functional deepEqual implementation:

function deepEqual(x, y) {
  return (x && y && typeof x === 'object' && typeof y === 'object') ?
    (Object.keys(x).length === Object.keys(y).length) &&
      Object.keys(x).reduce(function(isEqual, key) {
        return isEqual && deepEqual(x[key], y[key]);
      }, true) : (x === y);
}

Edit: version 2, using jib's suggestion and ES6 arrow functions:

function deepEqual(x, y) {
  const ok = Object.keys, tx = typeof x, ty = typeof y;
  return x && y && tx === 'object' && tx === ty ? (
    ok(x).length === ok(y).length &&
      ok(x).every(key => deepEqual(x[key], y[key]))
  ) : (x === y);
}

If you are comparing JSON objects you can use https://github.com/mirek/node-rus-diff

npm install rus-diff

Usage:

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

If two objects are different, a MongoDB compatible {$rename:{...}, $unset:{...}, $set:{...}} like object is returned.


Assuming that the order of the properties in the object is not changed.

JSON.stringify() works for deep and non-deep both types of objects, not very sure of performance aspects:

_x000D_
_x000D_
var object1 = {_x000D_
  key: "value"_x000D_
};_x000D_
_x000D_
var object2 = {_x000D_
  key: "value"_x000D_
};_x000D_
_x000D_
var object3 = {_x000D_
  key: "no value"_x000D_
};_x000D_
_x000D_
console.log('object1 and object2 are equal: ', JSON.stringify(object1) === JSON.stringify(object2));_x000D_
_x000D_
console.log('object2 and object3 are equal: ', JSON.stringify(object2) === JSON.stringify(object3));
_x000D_
_x000D_
_x000D_


Object equality check:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

The above test also works with arrays of objects in which case use a sort function as documented in http://www.w3schools.com/jsref/jsref_sort.asp

Might suffice for small arrays with flat JSON schemas.


If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.


If you are working in AngularJS, the angular.equals function will determine if two objects are equal. In Ember.js use isEqual.

  • angular.equals - See the docs or source for more on this method. It does a deep compare on arrays too.
  • Ember.js isEqual - See the docs or source for more on this method. It does not do a deep compare on arrays.

_x000D_
_x000D_
var purple = [{"purple": "drank"}];_x000D_
var drank = [{"purple": "drank"}];_x000D_
_x000D_
if(angular.equals(purple, drank)) {_x000D_
    document.write('got dat');_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
_x000D_
_x000D_
_x000D_


For those of you using Node, there is a convenient method called isDeepStrictEqual on the nativeutil library that can achieve this.

const util = require('util');

const obj1 = {
  foo: "bar",
  baz: [1, 2]
};

const obj2 = {
  foo: "bar",
  baz: [1, 2]
};


obj1 == obj2 // false
util.isDeepStrictEqual(obj1, obj2) // true

https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2


Sure, while we're at it I'll throw in my own reinvention of the wheel (I'm proud of the number of spokes and materials used):

////////////////////////////////////////////////////////////////////////////////

var equals = function ( objectA, objectB ) {
    var result = false,
        keysA,
        keysB;

    // Check if they are pointing at the same variable. If they are, no need to test further.
    if ( objectA === objectB ) {
        return true;
    }

    // Check if they are the same type. If they are not, no need to test further.
    if ( typeof objectA !== typeof objectB ) {
        return false;
    }

    // Check what kind of variables they are to see what sort of comparison we should make.
    if ( typeof objectA === "object" ) {
        // Check if they have the same constructor, so that we are comparing apples with apples.
        if ( objectA.constructor === objectA.constructor ) {
            // If we are working with Arrays...
            if ( objectA instanceof Array ) {
                // Check the arrays are the same length. If not, they cannot be the same.
                if ( objectA.length === objectB.length ) {
                    // Compare each element. They must be identical. If not, the comparison stops immediately and returns false.
                    return objectA.every(
                        function ( element, i ) {
                            return equals( element, objectB[ i ] );
                        }
                    );
                }
                // They are not the same length, and so are not identical.
                else {
                    return false;
                }
            }
            // If we are working with RegExps...
            else if ( objectA instanceof RegExp ) {
                // Return the results of a string comparison of the expression.
                return ( objectA.toString() === objectB.toString() );
            }
            // Else we are working with other types of objects...
            else {
                // Get the keys as arrays from both objects. This uses Object.keys, so no old browsers here.
                keysA = Object.keys( objectA );

                keysB = Object.keys( objectB );

                // Check the key arrays are the same length. If not, they cannot be the same.
                if ( keysA.length === keysB.length ) {
                    // Compare each property. They must be identical. If not, the comparison stops immediately and returns false.
                    return keysA.every(
                        function ( element ) {
                            return equals( objectA[ element ], objectB[ element ] );
                        }
                    );
                }
                // They do not have the same number of keys, and so are not identical.
                else {
                    return false;
                }
            }
        }
        // They don't have the same constructor.
        else {
            return false;
        }
    }
    // If they are both functions, let us do a string comparison.
    else if ( typeof objectA === "function" ) {
        return ( objectA.toString() === objectB.toString() );
    }
    // If a simple variable type, compare directly without coercion.
    else {
        return ( objectA === objectB );
    }

    // Return a default if nothing has already been returned.
    return result;
};

////////////////////////////////////////////////////////////////////////////////

It returns false as quickly as possible, but of course for a large object where the difference is deeply nested it could be less effective. In my own scenario, good handling of nested arrays is important.

Hope it helps someone needing this kind of 'wheel'.


_x000D_
_x000D_
function isDeepEqual(obj1, obj2, testPrototypes = false) {_x000D_
  if (obj1 === obj2) {_x000D_
    return true_x000D_
  }_x000D_
_x000D_
  if (typeof obj1 === "function" && typeof obj2 === "function") {_x000D_
    return obj1.toString() === obj2.toString()_x000D_
  }_x000D_
_x000D_
  if (obj1 instanceof Date && obj2 instanceof Date) {_x000D_
    return obj1.getTime() === obj2.getTime()_x000D_
  }_x000D_
_x000D_
  if (_x000D_
    Object.prototype.toString.call(obj1) !==_x000D_
      Object.prototype.toString.call(obj2) ||_x000D_
    typeof obj1 !== "object"_x000D_
  ) {_x000D_
    return false_x000D_
  }_x000D_
_x000D_
  const prototypesAreEqual = testPrototypes_x000D_
    ? isDeepEqual(_x000D_
        Object.getPrototypeOf(obj1),_x000D_
        Object.getPrototypeOf(obj2),_x000D_
        true_x000D_
      )_x000D_
    : true_x000D_
_x000D_
  const obj1Props = Object.getOwnPropertyNames(obj1)_x000D_
  const obj2Props = Object.getOwnPropertyNames(obj2)_x000D_
_x000D_
  return (_x000D_
    obj1Props.length === obj2Props.length &&_x000D_
    prototypesAreEqual &&_x000D_
    obj1Props.every(prop => isDeepEqual(obj1[prop], obj2[prop]))_x000D_
  )_x000D_
}_x000D_
_x000D_
console.log(isDeepEqual({key: 'one'}, {key: 'first'}))_x000D_
console.log(isDeepEqual({key: 'one'}, {key: 'one'}))
_x000D_
_x000D_
_x000D_


After so much of searches, i have found following working solution

function isEquivalent(a, b) {
   // Create arrays of property names
   var aProps = Object.getOwnPropertyNames(a);
   var bProps = Object.getOwnPropertyNames(b);

  // If number of properties is different, objects are not equivalent
  if (aProps.length != bProps.length) {
     return false;
  }

  for (var i = 0; i < aProps.length; i++) {
     var propName = aProps[i];

    // If values of same property are not equal, objects are not equivalent
     if (a[propName] !== b[propName]) {
         return false;
     }
  }

// If we made it this far, objects are considered equivalent
return true; }

For more info: Object Equality in JavaScript


const one={name:'mohit' , age:30};
//const two ={name:'mohit',age:30};
const two ={age:30,name:'mohit'};

function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);



// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
    return false;
}

for (var i = 0; i < aProps.length; i++) {
    var propName = aProps[i];

    // If values of same property are not equal,
    // objects are not equivalent
    if (a[propName] !== b[propName]) {
        return false;
    }
}

// If we made it this far, objects
// are considered equivalent
return true;
}

console.log(isEquivalent(one,two))

Just wanted to contribute my version of objects comparison utilizing some es6 features. It doesn't take an order into account. After converting all if/else's to ternary I've came with following:

function areEqual(obj1, obj2) {

    return Object.keys(obj1).every(key => {

            return obj2.hasOwnProperty(key) ?
                typeof obj1[key] === 'object' ?
                    areEqual(obj1[key], obj2[key]) :
                obj1[key] === obj2[key] :
                false;

        }
    )
}

The default equality operator in JavaScript for Objects yields true when they refer to the same location in memory.

var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

If you require a different equality operator you'll need to add an equals(other) method, or something like it to your classes and the specifics of your problem domain will determine what exactly that means.

Here's a playing card example:

function Card(rank, suit) {
  this.rank = rank;
  this.suit = suit;
  this.equals = function(other) {
     return other.rank == this.rank && other.suit == this.suit;
  };
}

var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");

queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true

_x000D_
_x000D_
     let user1 = {_x000D_
        name: "John",_x000D_
        address: {_x000D_
            line1: "55 Green Park Road",_x000D_
            line2: {_x000D_
              a:[1,2,3]_x000D_
            } _x000D_
        },_x000D_
        email:null_x000D_
        }_x000D_
    _x000D_
     let user2 = {_x000D_
        name: "John",_x000D_
        address: {_x000D_
            line1: "55 Green Park Road",_x000D_
            line2: {_x000D_
              a:[1,2,3]_x000D_
            } _x000D_
        },_x000D_
        email:null_x000D_
         }_x000D_
    _x000D_
    // Method 1_x000D_
    _x000D_
    function isEqual(a, b) {_x000D_
          return JSON.stringify(a) === JSON.stringify(b);_x000D_
    }_x000D_
    _x000D_
    // Method 2_x000D_
    _x000D_
    function isEqual(a, b) {_x000D_
      // checking type of a And b_x000D_
      if(typeof a !== 'object' || typeof b !== 'object') {_x000D_
        return false;_x000D_
      }_x000D_
      _x000D_
      // Both are NULL_x000D_
      if(!a && !b ) {_x000D_
         return true;_x000D_
      } else if(!a || !b) {_x000D_
         return false;_x000D_
      }_x000D_
      _x000D_
      let keysA = Object.keys(a);_x000D_
      let keysB = Object.keys(b);_x000D_
      if(keysA.length !== keysB.length) {_x000D_
        return false;_x000D_
      }_x000D_
      for(let key in a) {_x000D_
       if(!(key in b)) {_x000D_
         return false;_x000D_
       }_x000D_
        _x000D_
       if(typeof a[key] === 'object') {_x000D_
         if(!isEqual(a[key], b[key]))_x000D_
           {_x000D_
             return false;_x000D_
           }_x000D_
       } else {_x000D_
         if(a[key] !== b[key]) {_x000D_
           return false;_x000D_
         }_x000D_
       }_x000D_
      }_x000D_
      _x000D_
      return true;_x000D_
    }_x000D_
_x000D_
_x000D_
_x000D_
console.log(isEqual(user1,user2));
_x000D_
_x000D_
_x000D_


Needing a more generic object comparison function than had been posted, I cooked up the following. Critique appreciated...

Object.prototype.equals = function(iObj) {
  if (this.constructor !== iObj.constructor)
    return false;
  var aMemberCount = 0;
  for (var a in this) {
    if (!this.hasOwnProperty(a))
      continue;
    if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
      return false;
    ++aMemberCount;
  }
  for (var a in iObj)
    if (iObj.hasOwnProperty(a))
      --aMemberCount;
  return aMemberCount ? false : true;
}

A simple solution to this issue that many people don't realize is to sort the JSON strings (per character). This is also usually faster than the other solutions mentioned here:

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

Another useful thing about this method is you can filter comparisons by passing a "replacer" function to the JSON.stringify functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter). The following will only compare all objects keys that are named "derp":

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

function isEqual(obj1, obj2){
    type1 = typeof(obj1);
    type2 = typeof(obj2);
    if(type1===type2){
        switch (type1){
            case "object": return JSON.stringify(obj1)===JSON.stringify(obj2);
            case "function": return eval(obj1).toString()===eval(obj2).toString();
            default: return obj1==obj2;
        }
    }
    return false;
}//have not tried but should work.

Here's a pretty clean CoffeeScript version of how you could do this:

Object::equals = (other) ->
  typeOf = Object::toString

  return false if typeOf.call(this) isnt typeOf.call(other)
  return `this == other` unless typeOf.call(other) is '[object Object]' or
                                typeOf.call(other) is '[object Array]'

  (return false unless this[key].equals other[key]) for key, value of this
  (return false if typeof this[key] is 'undefined') for key of other

  true

Here are the tests:

  describe "equals", ->

    it "should consider two numbers to be equal", ->
      assert 5.equals(5)

    it "should consider two empty objects to be equal", ->
      assert {}.equals({})

    it "should consider two objects with one key to be equal", ->
      assert {a: "banana"}.equals {a: "banana"}

    it "should consider two objects with keys in different orders to be equal", ->
      assert {a: "banana", kendall: "garrus"}.equals {kendall: "garrus", a: "banana"}

    it "should consider two objects with nested objects to be equal", ->
      assert {a: {fruit: "banana"}}.equals {a: {fruit: "banana"}}

    it "should consider two objects with nested objects that are jumbled to be equal", ->
      assert {a: {a: "banana", kendall: "garrus"}}.equals {a: {kendall: "garrus", a: "banana"}}

    it "should consider two objects with arrays as values to be equal", ->
      assert {a: ["apple", "banana"]}.equals {a: ["apple", "banana"]}



    it "should not consider an object to be equal to null", ->
      assert !({a: "banana"}.equals null)

    it "should not consider two objects with different keys to be equal", ->
      assert !({a: "banana"}.equals {})

    it "should not consider two objects with different values to be equal", ->
      assert !({a: "banana"}.equals {a: "grapefruit"})

Here is a very basic approach to checking an object's "value equality".

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

function isEquivalent(a, b) {
    // Create arrays of property names

    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different, objects are not equivalent

    if (aProps.length != bProps.length) {
        return false;
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];

        // If values of same property are not equal, objects are not equivalent
        if (a[propName] !== b[propName]) {
           return false;
        }
    }

    // If we made it this far, objects are considered equivalent
    return true;
}

// Outputs: true
console.log(isEquivalent(john, bobby));

Demo - JSFiddle

As you can see, to check the objects' "value equality" we essentially have to iterate over every property in the objects to see whether they are equal. And while this simple implementation works for our example, there are a lot of cases that it doesn't handle. For instance:

  • What if one of the property values is itself an object?
  • What if one of the property values is NaN (the only value in JavaScript that is not equal to itself?)
  • What if a has a property with value undefined, while b doesn't have this property (which thus evaluates to undefined?)

For a robust method of checking objects' "value equality" it is better to rely on a well-tested library that covers the various edge cases like Underscore.

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

// Outputs: true
console.log(_.isEqual(john, bobby));

Demo - JSFiddle


I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.


  1. sort the objects (dictionary)
  2. compare JSON string

    function areTwoDictsEqual(dictA, dictB) {
        function sortDict(dict) {
            var keys = Object.keys(dict);
            keys.sort();
    
            var newDict = {};
            for (var i=0; i<keys.length; i++) {
                var key = keys[i];
                var value = dict[key];
                newDict[key] = value;
            } 
            return newDict;
        }
    
        return JSON.stringify(sortDict(dictA)) == JSON.stringify(sortDict(dictB));
    }
    

you can use _.isEqual(obj1, obj2) from the underscore.js library.

Here is an example:

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

See the official documentation from here: http://underscorejs.org/#isEqual


Here's a version of the stringify trick that is less typing and works in a lot of cases for trivial JSON data comparisons.

var obj1Fingerprint = JSON.stringify(obj1).replace(/\{|\}/g,'').split(',').sort().join(',');
var obj2Fingerprint = JSON.stringify(obj2).replace(/\{|\}/g,'').split(',').sort().join(',');
if ( obj1Fingerprint === obj2Fingerprint) { ... } else { ... }

This is a simple Javascript function to compare two objects having simple key-value pairs. The function will return an array of strings, where each string is a path to an inequality between the two objects.

function compare(a,b) {
    var paths = [];
    [...new Set(Object.keys(a).concat(Object.keys(b)))].forEach(key=>{
        if(typeof a[key] === 'object' && typeof b[key] === 'object') {
            var results = compare(a[key], b[key]);
            if(JSON.stringify(results)!=='[]') {
                paths.push(...results.map(result=>key.concat("=>"+result)));
            }
        }
        else if (a[key]!==b[key]) {
            paths.push(key);
        }
    })
    return paths;
}

If you only want to compare two objects without knowing the paths to inequalities, you can do it as follows:

if(JSON.stringify(compare(object1, object2))==='[]') {
   // the two objects are equal
} else {
   // the two objects are not equal
}

This is an addition for all the above, not a replacement. If you need to fast shallow-compare objects without need to check extra recursive cases. Here is a shot.

This compares for: 1) Equality of number of own properties, 2) Equality of key names, 3) if bCompareValues == true, Equality of corresponding property values and their types (triple equality)

var shallowCompareObjects = function(o1, o2, bCompareValues) {
    var s, 
        n1 = 0,
        n2 = 0,
        b  = true;

    for (s in o1) { n1 ++; }
    for (s in o2) { 
        if (!o1.hasOwnProperty(s)) {
            b = false;
            break;
        }
        if (bCompareValues && o1[s] !== o2[s]) {
            b = false;
            break;
        }
        n2 ++;
    }
    return b && n1 == n2;
}

I've written a small library that runs on Node.js and the browser called compare.js. It offers the usual comparison operators, such as ==, !=, >, >=, <, <= and identity on all data types of JavaScript.

E.g., you can use

cmp.eq(obj1, obj2);

and this will check for equality (using a deep-equal approach). Otherwise, if you do

cmp.id(obj1, obj2);

it will compare by reference, hence check for identity. You can also use < and > on objects, which mean subset and superset.

compare.js is covered by nearly 700 unit tests, hence it should hopefully not have too many bugs ;-).

You can find it on https://github.com/goloroden/compare.js for free, it is open-sourced under the MIT license.


I use this comparable function to produce copies of my objects that are JSON comparable:

_x000D_
_x000D_
var comparable = o => (typeof o != 'object' || !o)? o :_x000D_
  Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});_x000D_
_x000D_
// Demo:_x000D_
_x000D_
var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };_x000D_
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };_x000D_
_x000D_
console.log(JSON.stringify(comparable(a)));_x000D_
console.log(JSON.stringify(comparable(b)));_x000D_
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));
_x000D_
<div id="div"></div>
_x000D_
_x000D_
_x000D_

Comes in handy in tests (most test frameworks have an is function). E.g.

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

If a difference is caught, strings get logged, making differences spottable:

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

I'm not a Javascript expert, but here is one simple attempt to solve it. I check for three things:

  1. Is it an object and also that it is not null because typeof null is object.
  2. If the property count of the two objects is the same? If not they are not equal.
  3. Loop through properties of one and check if corresponding property has same value in second object.

_x000D_
_x000D_
function deepEqual (first, second) {_x000D_
  // Not equal if either is not an object or is null._x000D_
  if (!isObject(first) || !isObject(second) ) return false;_x000D_
_x000D_
  // If properties count is different_x000D_
  if (keys(first).length != keys(second).length) return false;_x000D_
_x000D_
  // Return false if any property value is different._x000D_
  for(prop in first){_x000D_
    if (first[prop] != second[prop]) return false;_x000D_
  }_x000D_
  return true;_x000D_
}_x000D_
_x000D_
// Checks if argument is an object and is not null_x000D_
function isObject(obj) {_x000D_
  return (typeof obj === "object" && obj != null);_x000D_
}_x000D_
_x000D_
// returns arrays of object keys_x000D_
function keys (obj) {_x000D_
  result = [];_x000D_
  for(var key in obj){_x000D_
    result.push(key);_x000D_
  }_x000D_
  return result;_x000D_
}_x000D_
_x000D_
// Some test code_x000D_
obj1 = {_x000D_
  name: 'Singh',_x000D_
  age: 20_x000D_
}_x000D_
_x000D_
obj2 = {_x000D_
  age: 20,_x000D_
  name: 'Singh'_x000D_
}_x000D_
_x000D_
obj3 = {_x000D_
  name: 'Kaur',_x000D_
  age: 19_x000D_
}_x000D_
_x000D_
console.log(deepEqual(obj1, obj2));_x000D_
console.log(deepEqual(obj1, obj3));
_x000D_
_x000D_
_x000D_


This is a classic javascript question! I created a method to check deep object equality with the feature of being able to select properties to ignore from comparison. Arguments are the two objects to compare, plus, an optional array of stringified property-to-ignore relative path.

function isObjectEqual( o1, o2, ignorePropsArr=[]) {
    // Deep Clone objects
    let _obj1 = JSON.parse(JSON.stringify(o1)),
        _obj2 = JSON.parse(JSON.stringify(o2));
    // Remove props to ignore
    ignorePropsArr.map( p => { 
        eval('_obj1.'+p+' = _obj2.'+p+' = "IGNORED"');
    });
    // compare as strings
    let s1 = JSON.stringify(_obj1),
        s2 = JSON.stringify(_obj2);
    // return [s1==s2,s1,s2];
    return s1==s2;
}

// Objects 0 and 1 are exact equals
obj0 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj1 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj2 = { price: 66544.12, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj3 = { price: 66544.13, RSIs: [0.000432334, 0.00046531], candles: {A: 541, B: 321, C: 4322}}
obj4 = { price: 66544.14, RSIs: [0.000432334, 0.00046530], candles: {A: 543, B: 321, C: 4322}}

isObjectEqual(obj0,obj1) // true
isObjectEqual(obj0,obj2) // false
isObjectEqual(obj0,obj2,['price']) // true
isObjectEqual(obj0,obj3,['price']) // false
isObjectEqual(obj0,obj3,['price','candles.A']) // true
isObjectEqual(obj0,obj4,['price','RSIs[1]'])   // true

I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.


Lot's of good thoughts here! Here is my version of deep equal. I posted it on github and wrote some tests around it. It's hard to cover all the possible cases and sometimes it's unnecessary to do so.

I covered NaN !== NaN as well as circular dependencies.

https://github.com/ryancat/simple-deep-equal/blob/master/index.js


If you have a deep copy function handy, you can use the following trick to still use JSON.stringify while matching the order of properties:

function equals(obj1, obj2) {
    function _equals(obj1, obj2) {
        return JSON.stringify(obj1)
            === JSON.stringify($.extend(true, {}, obj1, obj2));
    }
    return _equals(obj1, obj2) && _equals(obj2, obj1);
}

Demo: http://jsfiddle.net/CU3vb/3/

Rationale:

Since the properties of obj1 are copied to the clone one by one, their order in the clone will be preserved. And when the properties of obj2 are copied to the clone, since properties already existing in obj1 will simply be overwritten, their orders in the clone will be preserved.


Here's a pretty clean CoffeeScript version of how you could do this:

Object::equals = (other) ->
  typeOf = Object::toString

  return false if typeOf.call(this) isnt typeOf.call(other)
  return `this == other` unless typeOf.call(other) is '[object Object]' or
                                typeOf.call(other) is '[object Array]'

  (return false unless this[key].equals other[key]) for key, value of this
  (return false if typeof this[key] is 'undefined') for key of other

  true

Here are the tests:

  describe "equals", ->

    it "should consider two numbers to be equal", ->
      assert 5.equals(5)

    it "should consider two empty objects to be equal", ->
      assert {}.equals({})

    it "should consider two objects with one key to be equal", ->
      assert {a: "banana"}.equals {a: "banana"}

    it "should consider two objects with keys in different orders to be equal", ->
      assert {a: "banana", kendall: "garrus"}.equals {kendall: "garrus", a: "banana"}

    it "should consider two objects with nested objects to be equal", ->
      assert {a: {fruit: "banana"}}.equals {a: {fruit: "banana"}}

    it "should consider two objects with nested objects that are jumbled to be equal", ->
      assert {a: {a: "banana", kendall: "garrus"}}.equals {a: {kendall: "garrus", a: "banana"}}

    it "should consider two objects with arrays as values to be equal", ->
      assert {a: ["apple", "banana"]}.equals {a: ["apple", "banana"]}



    it "should not consider an object to be equal to null", ->
      assert !({a: "banana"}.equals null)

    it "should not consider two objects with different keys to be equal", ->
      assert !({a: "banana"}.equals {})

    it "should not consider two objects with different values to be equal", ->
      assert !({a: "banana"}.equals {a: "grapefruit"})

I faced the same problem and deccided to write my own solution. But because I want to also compare Arrays with Objects and vice-versa, I crafted a generic solution. I decided to add the functions to the prototype, but one can easily rewrite them to standalone functions. Here is the code:

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

This Algorithm is split into two parts; The equals function itself and a function to find the numeric index of a property in an array / object. The find function is only needed because indexof only finds numbers and strings and no objects .

One can call it like this:

({a: 1, b: "h"}).equals({a: 1, b: "h"});

The function either returns true or false, in this case true. The algorithm als allows comparison between very complex objects:

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

The upper example will return true, even tho the properties have a different ordering. One small detail to look out for: This code also checks for the same type of two variables, so "3" is not the same as 3.


I know this is a bit old, but I would like to add a solution that I came up with for this problem. I had an object and I wanted to know when its data changed. "something similar to Object.observe" and what I did was:

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

This here can be duplicated and create an other set of arrays to compare the values and keys. It is very simple because they are now arrays and will return false if objects have different sizes.


If you have a deep copy function handy, you can use the following trick to still use JSON.stringify while matching the order of properties:

function equals(obj1, obj2) {
    function _equals(obj1, obj2) {
        return JSON.stringify(obj1)
            === JSON.stringify($.extend(true, {}, obj1, obj2));
    }
    return _equals(obj1, obj2) && _equals(obj2, obj1);
}

Demo: http://jsfiddle.net/CU3vb/3/

Rationale:

Since the properties of obj1 are copied to the clone one by one, their order in the clone will be preserved. And when the properties of obj2 are copied to the clone, since properties already existing in obj1 will simply be overwritten, their orders in the clone will be preserved.


Here's a version of the stringify trick that is less typing and works in a lot of cases for trivial JSON data comparisons.

var obj1Fingerprint = JSON.stringify(obj1).replace(/\{|\}/g,'').split(',').sort().join(',');
var obj2Fingerprint = JSON.stringify(obj2).replace(/\{|\}/g,'').split(',').sort().join(',');
if ( obj1Fingerprint === obj2Fingerprint) { ... } else { ... }

The default equality operator in JavaScript for Objects yields true when they refer to the same location in memory.

var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

If you require a different equality operator you'll need to add an equals(other) method, or something like it to your classes and the specifics of your problem domain will determine what exactly that means.

Here's a playing card example:

function Card(rank, suit) {
  this.rank = rank;
  this.suit = suit;
  this.equals = function(other) {
     return other.rank == this.rank && other.suit == this.suit;
  };
}

var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");

queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true

Why reinvent the wheel? Give Lodash a try. It has a number of must-have functions such as isEqual().

_.isEqual(object, other);

It will brute force check each key value - just like the other examples on this page - using ECMAScript 5 and native optimizations if they're available in the browser.

Note: Previously this answer recommended Underscore.js, but lodash has done a better job of getting bugs fixed and addressing issues with consistency.


Simplest and logical solutions for comparing everything Like Object, Array, String, Int...

JSON.stringify({a: val1}) === JSON.stringify({a: val2})

Note:

  • you need to replace val1and val2 with your Object
  • for the object, you have to sort(by key) recursively for both side objects

_x000D_
_x000D_
     let user1 = {_x000D_
        name: "John",_x000D_
        address: {_x000D_
            line1: "55 Green Park Road",_x000D_
            line2: {_x000D_
              a:[1,2,3]_x000D_
            } _x000D_
        },_x000D_
        email:null_x000D_
        }_x000D_
    _x000D_
     let user2 = {_x000D_
        name: "John",_x000D_
        address: {_x000D_
            line1: "55 Green Park Road",_x000D_
            line2: {_x000D_
              a:[1,2,3]_x000D_
            } _x000D_
        },_x000D_
        email:null_x000D_
         }_x000D_
    _x000D_
    // Method 1_x000D_
    _x000D_
    function isEqual(a, b) {_x000D_
          return JSON.stringify(a) === JSON.stringify(b);_x000D_
    }_x000D_
    _x000D_
    // Method 2_x000D_
    _x000D_
    function isEqual(a, b) {_x000D_
      // checking type of a And b_x000D_
      if(typeof a !== 'object' || typeof b !== 'object') {_x000D_
        return false;_x000D_
      }_x000D_
      _x000D_
      // Both are NULL_x000D_
      if(!a && !b ) {_x000D_
         return true;_x000D_
      } else if(!a || !b) {_x000D_
         return false;_x000D_
      }_x000D_
      _x000D_
      let keysA = Object.keys(a);_x000D_
      let keysB = Object.keys(b);_x000D_
      if(keysA.length !== keysB.length) {_x000D_
        return false;_x000D_
      }_x000D_
      for(let key in a) {_x000D_
       if(!(key in b)) {_x000D_
         return false;_x000D_
       }_x000D_
        _x000D_
       if(typeof a[key] === 'object') {_x000D_
         if(!isEqual(a[key], b[key]))_x000D_
           {_x000D_
             return false;_x000D_
           }_x000D_
       } else {_x000D_
         if(a[key] !== b[key]) {_x000D_
           return false;_x000D_
         }_x000D_
       }_x000D_
      }_x000D_
      _x000D_
      return true;_x000D_
    }_x000D_
_x000D_
_x000D_
_x000D_
console.log(isEqual(user1,user2));
_x000D_
_x000D_
_x000D_


I'm not a Javascript expert, but here is one simple attempt to solve it. I check for three things:

  1. Is it an object and also that it is not null because typeof null is object.
  2. If the property count of the two objects is the same? If not they are not equal.
  3. Loop through properties of one and check if corresponding property has same value in second object.

_x000D_
_x000D_
function deepEqual (first, second) {_x000D_
  // Not equal if either is not an object or is null._x000D_
  if (!isObject(first) || !isObject(second) ) return false;_x000D_
_x000D_
  // If properties count is different_x000D_
  if (keys(first).length != keys(second).length) return false;_x000D_
_x000D_
  // Return false if any property value is different._x000D_
  for(prop in first){_x000D_
    if (first[prop] != second[prop]) return false;_x000D_
  }_x000D_
  return true;_x000D_
}_x000D_
_x000D_
// Checks if argument is an object and is not null_x000D_
function isObject(obj) {_x000D_
  return (typeof obj === "object" && obj != null);_x000D_
}_x000D_
_x000D_
// returns arrays of object keys_x000D_
function keys (obj) {_x000D_
  result = [];_x000D_
  for(var key in obj){_x000D_
    result.push(key);_x000D_
  }_x000D_
  return result;_x000D_
}_x000D_
_x000D_
// Some test code_x000D_
obj1 = {_x000D_
  name: 'Singh',_x000D_
  age: 20_x000D_
}_x000D_
_x000D_
obj2 = {_x000D_
  age: 20,_x000D_
  name: 'Singh'_x000D_
}_x000D_
_x000D_
obj3 = {_x000D_
  name: 'Kaur',_x000D_
  age: 19_x000D_
}_x000D_
_x000D_
console.log(deepEqual(obj1, obj2));_x000D_
console.log(deepEqual(obj1, obj3));
_x000D_
_x000D_
_x000D_


A quick "hack" to tell if two objects are similar, is to use their toString() methods. If you're checking objects A and B, make sure A and B have meaningful toString() methods and check that the strings they return are the same.

This isn't a panacea, but it can be useful sometimes in the right situations.


Are you trying to test if two objects are the equal? ie: their properties are equal?

If this is the case, you'll probably have noticed this situation:

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

you might have to do something like this:

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.


A quick "hack" to tell if two objects are similar, is to use their toString() methods. If you're checking objects A and B, make sure A and B have meaningful toString() methods and check that the strings they return are the same.

This isn't a panacea, but it can be useful sometimes in the right situations.


Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).


I have a much shorter function that will go deep into all sub objects or arrays. It is as efficient as JSON.stringify(obj1) === JSON.stringify(obj2) but JSON.stringify will not work if the order is not the same (as mentioned here).

var obj1 = { a : 1, b : 2 };
var obj2 = { b : 2, a : 1 };

console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false

The function would also be a good start if you want to do something with the unequal values.

_x000D_
_x000D_
function arr_or_obj(v)_x000D_
{ return !!v && (v.constructor === Object || v.constructor === Array); }_x000D_
_x000D_
function deep_equal(v1, v2)_x000D_
{_x000D_
    if (arr_or_obj(v1) && arr_or_obj(v2) && v1.constructor === v2.constructor)_x000D_
    {_x000D_
        if (Object.keys(v1).length === Object.keys(v2).length) // check the length_x000D_
        for (var i in v1)_x000D_
        {_x000D_
            if (!deep_equal(v1[i], v2[i]))_x000D_
            { return false; }_x000D_
        }_x000D_
        else_x000D_
        { return false; }_x000D_
    }_x000D_
    else if (v1 !== v2)_x000D_
    { return false; }_x000D_
_x000D_
    return true;_x000D_
}_x000D_
_x000D_
//////////////////////////////////////////////////////////////////_x000D_
//////////////////////////////////////////////////////////////////_x000D_
_x000D_
var obj1 = [_x000D_
    {_x000D_
        hat : {_x000D_
            cap : ['something', null ],_x000D_
            helmet : [ 'triple eight', 'pro-tec' ]_x000D_
        },_x000D_
        shoes : [ 'loafer', 'penny' ]_x000D_
    },_x000D_
    {_x000D_
        beers : [ 'budweiser', 'busch' ],_x000D_
        wines : [ 'barefoot', 'yellow tail' ]_x000D_
    }_x000D_
];_x000D_
_x000D_
var obj2 = [_x000D_
    {_x000D_
        shoes : [ 'loafer', 'penny' ], // same even if the order is different_x000D_
        hat : {_x000D_
            cap : ['something', null ],_x000D_
            helmet : [ 'triple eight', 'pro-tec' ]_x000D_
        }_x000D_
    },_x000D_
    {_x000D_
        beers : [ 'budweiser', 'busch' ],_x000D_
        wines : [ 'barefoot', 'yellow tail' ]_x000D_
    }_x000D_
];_x000D_
_x000D_
console.log(deep_equal(obj1, obj2)); // true_x000D_
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false_x000D_
console.log(deep_equal([], [])); // true_x000D_
console.log(deep_equal({}, {})); // true_x000D_
console.log(deep_equal([], {})); // false
_x000D_
_x000D_
_x000D_

And if you want to add support for Function, Date and RegExp, you can add this at the beginning of deep_equal (not tested):

if ((typeof obj1 === 'function' && typeof obj2 === 'function') ||
(obj1 instanceof Date && obj2 instanceof Date) ||
(obj1 instanceof RegExp && obj2 instanceof RegExp))
{
    obj1 = obj1.toString();
    obj2 = obj2.toString();
}

In Node.js, you can use its native require("assert").deepStrictEqual. More info: http://nodejs.org/api/assert.html

For example:

var assert = require("assert");
assert.deepStrictEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError

Another example that returns true / false instead of returning errors:

var assert = require("assert");

function deepEqual(a, b) {
    try {
      assert.deepEqual(a, b);
    } catch (error) {
      if (error.name === "AssertionError") {
        return false;
      }
      throw error;
    }
    return true;
};

I've implemented a method that takes two jsons and checks to see if their keys have the same values using recursion. I used another question to solve this.

_x000D_
_x000D_
const arraysEqual = (a, b) => {_x000D_
    if (a === b)_x000D_
        return true;_x000D_
    if (a === null || b === null)_x000D_
        return false;_x000D_
    if (a.length !== b.length)_x000D_
        return false;_x000D_
_x000D_
    // If you don't care about the order of the elements inside_x000D_
    // the array, you should sort both arrays here._x000D_
_x000D_
    for (let i = 0; i < a.length; ++i) {_x000D_
        if (a[i] !== b[i])_x000D_
            return false;_x000D_
    }_x000D_
    return true;_x000D_
};_x000D_
_x000D_
const jsonsEqual = (a, b) => {_x000D_
_x000D_
  if(typeof a !== 'object' || typeof b !== 'object')_x000D_
      return false;_x000D_
_x000D_
  if (Object.keys(a).length === Object.keys(b).length) { // if items have the same size_x000D_
      let response = true;_x000D_
_x000D_
      for (let key in a) {_x000D_
          if (!b[key]) // if not key_x000D_
              response = false;_x000D_
          if (typeof a[key] !== typeof b[key]) // if typeof doesn't equals_x000D_
              response = false;_x000D_
          else {_x000D_
              if (Array.isArray(a[key])) // if array_x000D_
                  response = arraysEqual(a[key], b[key]);_x000D_
              else if (typeof a[key] === 'object') // if another json_x000D_
                  response = jsonsEqual(a[key], b[key]);_x000D_
              else if (a[key] !== b[key])  // not equals_x000D_
                  response = false;_x000D_
          }_x000D_
          if (!response) // return if one item isn't equal_x000D_
              return false;_x000D_
      }_x000D_
  } else_x000D_
      return false;_x000D_
_x000D_
  return true;_x000D_
};_x000D_
_x000D_
const json1 = { _x000D_
  a: 'a', _x000D_
  b: 'asd', _x000D_
  c: [_x000D_
    '1',_x000D_
    2,_x000D_
    2.5,_x000D_
    '3', _x000D_
    {_x000D_
      d: 'asd',_x000D_
      e: [_x000D_
        1.6,_x000D_
        { _x000D_
          f: 'asdasd',_x000D_
          g: '123'_x000D_
        }_x000D_
      ]_x000D_
    }_x000D_
  ],_x000D_
  h: 1,_x000D_
  i: 1.2,_x000D_
};_x000D_
_x000D_
const json2 = {_x000D_
  a: 'nops',_x000D_
  b: 'asd'_x000D_
};_x000D_
_x000D_
const json3 = { _x000D_
  a: 'h', _x000D_
  b: '484', _x000D_
  c: [_x000D_
    3,_x000D_
    4.5,_x000D_
    '2ss', _x000D_
    {_x000D_
      e: [_x000D_
        { _x000D_
          f: 'asdasd',_x000D_
          g: '123'_x000D_
        }_x000D_
      ]_x000D_
    }_x000D_
  ],_x000D_
  h: 1,_x000D_
  i: 1.2,_x000D_
};_x000D_
_x000D_
const result = jsonsEqual(json1,json2);_x000D_
//const result = jsonsEqual(json1,json3);_x000D_
//const result = jsonsEqual(json1,json1);_x000D_
_x000D_
if(result) // is equal_x000D_
  $('#result').text("Jsons are the same")_x000D_
else_x000D_
  $('#result').text("Jsons aren't equals")
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
_x000D_
<div id="result"></div>
_x000D_
_x000D_
_x000D_


Object equality check:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

The above test also works with arrays of objects in which case use a sort function as documented in http://www.w3schools.com/jsref/jsref_sort.asp

Might suffice for small arrays with flat JSON schemas.


I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.


I need to mock jQuery POST requests, so the equality that matters to me is that both objects have the same set of properties (none missing in either object), and that each property value is "equal" (according to this definition). I don't care about the objects having mismatching methods.

Here's what I'll be using, it should be good enough for my specific requirements:

function PostRequest() {
    for (var i = 0; i < arguments.length; i += 2) {
        this[arguments[i]] = arguments[i+1];
    }

    var compare = function(u, v) {
        if (typeof(u) != typeof(v)) {
            return false;
        }

        var allkeys = {};
        for (var i in u) {
            allkeys[i] = 1;
        }
        for (var i in v) {
            allkeys[i] = 1;
        }
        for (var i in allkeys) {
            if (u.hasOwnProperty(i) != v.hasOwnProperty(i)) {
                if ((u.hasOwnProperty(i) && typeof(u[i]) == 'function') ||
                    (v.hasOwnProperty(i) && typeof(v[i]) == 'function')) {
                    continue;
                } else {
                    return false;
                }
            }
            if (typeof(u[i]) != typeof(v[i])) {
                return false;
            }
            if (typeof(u[i]) == 'object') {
                if (!compare(u[i], v[i])) {
                    return false;
                }
            } else {
                if (u[i] !== v[i]) {
                    return false;
                }
            }
        }

        return true;
    };

    this.equals = function(o) {
        return compare(this, o);
    };

    return this;
}

Use like so:

foo = new PostRequest('text', 'hello', 'html', '<p>hello</p>');
foo.equals({ html: '<p>hello</p>', text: 'hello' });

My version, which includes the chain of where the difference is found, and what the difference is.

function DeepObjectCompare(O1, O2)
{
    try {
        DOC_Val(O1, O2, ['O1->O2', O1, O2]);
        return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
    } catch(e) {
        console.log(e.Chain);
        throw(e);
    }
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
    this.Reason=Reason;
    this.Chain=Chain;
    this.Val1=Val1;
    this.Val2=Val2;
}

function DOC_Val(Val1, Val2, Chain)
{
    function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }

    if(typeof(Val1)!==typeof(Val2))
        return DoThrow('Type Mismatch');
    if(Val1===null || Val1===undefined)
        return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
    if(Val1.constructor!==Val2.constructor)
        return DoThrow('Constructor mismatch');
    switch(typeof(Val1))
    {
        case 'object':
            for(var m in Val1)
            {
                if(!Val1.hasOwnProperty(m))
                    continue;
                var CurChain=Chain.concat([m]);
                if(!Val2.hasOwnProperty(m))
                    return DoThrow('Val2 missing property', CurChain);
                DOC_Val(Val1[m], Val2[m], CurChain);
            }
            return true;
        case 'number':
            if(Number.isNaN(Val1))
                return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
        case 'string':
        case 'boolean':
            return Val1!==Val2 ? DoThrow('Value mismatch') : true;
        case 'function':
            if(Val1.prototype!==Val2.prototype)
                return DoThrow('Prototype mismatch');
            if(Val1!==Val2)
                return DoThrow('Function mismatch');
            return true;
        default:
            return DoThrow('Val1 is unknown type');
    }
}

This is an addition for all the above, not a replacement. If you need to fast shallow-compare objects without need to check extra recursive cases. Here is a shot.

This compares for: 1) Equality of number of own properties, 2) Equality of key names, 3) if bCompareValues == true, Equality of corresponding property values and their types (triple equality)

var shallowCompareObjects = function(o1, o2, bCompareValues) {
    var s, 
        n1 = 0,
        n2 = 0,
        b  = true;

    for (s in o1) { n1 ++; }
    for (s in o2) { 
        if (!o1.hasOwnProperty(s)) {
            b = false;
            break;
        }
        if (bCompareValues && o1[s] !== o2[s]) {
            b = false;
            break;
        }
        n2 ++;
    }
    return b && n1 == n2;
}

Yeah, another answer...

_x000D_
_x000D_
Object.prototype.equals = function (object) {_x000D_
    if (this.constructor !== object.constructor) return false;_x000D_
    if (Object.keys(this).length !== Object.keys(object).length) return false;_x000D_
    var obk;_x000D_
    for (obk in object) {_x000D_
        if (this[obk] !== object[obk])_x000D_
            return false;_x000D_
    }_x000D_
    return true;_x000D_
}_x000D_
_x000D_
var aaa = JSON.parse('{"name":"mike","tel":"1324356584"}');_x000D_
var bbb = JSON.parse('{"tel":"1324356584","name":"mike"}');_x000D_
var ccc = JSON.parse('{"name":"mike","tel":"584"}');_x000D_
var ddd = JSON.parse('{"name":"mike","tel":"1324356584", "work":"nope"}');_x000D_
_x000D_
$("#ab").text(aaa.equals(bbb));_x000D_
$("#ba").text(bbb.equals(aaa));_x000D_
$("#bc").text(bbb.equals(ccc));_x000D_
$("#ad").text(aaa.equals(ddd));
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
aaa equals bbb? <span id="ab"></span> <br/>_x000D_
bbb equals aaa? <span id="ba"></span> <br/>_x000D_
bbb equals ccc? <span id="bc"></span> <br/>_x000D_
aaa equals ddd? <span id="ad"></span>
_x000D_
_x000D_
_x000D_


Some of the following solutions have problems with performance, functionality and style... They are not thought through enough, and some of them fail for different cases. I tried to address this problem in my own solution, and I would really much appreciate your feedback:

http://stamat.wordpress.com/javascript-object-comparison/

//Returns the object's class, Array, Date, RegExp, Object are of interest to us
var getClass = function(val) {
    return Object.prototype.toString.call(val)
        .match(/^\[object\s(.*)\]$/)[1];
};

//Defines the type of the value, extended typeof
var whatis = function(val) {

    if (val === undefined)
        return 'undefined';
    if (val === null)
        return 'null';

    var type = typeof val;

    if (type === 'object')
        type = getClass(val).toLowerCase();

    if (type === 'number') {
        if (val.toString().indexOf('.') > 0)
            return 'float';
        else
        return 'integer';
    }

    return type;
   };

var compareObjects = function(a, b) {
    if (a === b)
        return true;
    for (var i in a) {
        if (b.hasOwnProperty(i)) {
            if (!equal(a[i],b[i])) return false;
        } else {
            return false;
        }
    }

    for (var i in b) {
        if (!a.hasOwnProperty(i)) {
            return false;
        }
    }
    return true;
};

var compareArrays = function(a, b) {
    if (a === b)
        return true;
    if (a.length !== b.length)
        return false;
    for (var i = 0; i < a.length; i++){
        if(!equal(a[i], b[i])) return false;
    };
    return true;
};

var _equal = {};
_equal.array = compareArrays;
_equal.object = compareObjects;
_equal.date = function(a, b) {
    return a.getTime() === b.getTime();
};
_equal.regexp = function(a, b) {
    return a.toString() === b.toString();
};
//  uncoment to support function as string compare
//  _equal.fucntion =  _equal.regexp;



/*
 * Are two values equal, deep compare for objects and arrays.
 * @param a {any}
 * @param b {any}
 * @return {boolean} Are equal?
 */
var equal = function(a, b) {
    if (a !== b) {
        var atype = whatis(a), btype = whatis(b);

        if (atype === btype)
            return _equal.hasOwnProperty(atype) ? _equal[atype](a, b) : a==b;

        return false;
    }

    return true;
};

Assuming that the order of the properties in the object is not changed.

JSON.stringify() works for deep and non-deep both types of objects, not very sure of performance aspects:

_x000D_
_x000D_
var object1 = {_x000D_
  key: "value"_x000D_
};_x000D_
_x000D_
var object2 = {_x000D_
  key: "value"_x000D_
};_x000D_
_x000D_
var object3 = {_x000D_
  key: "no value"_x000D_
};_x000D_
_x000D_
console.log('object1 and object2 are equal: ', JSON.stringify(object1) === JSON.stringify(object2));_x000D_
_x000D_
console.log('object2 and object3 are equal: ', JSON.stringify(object2) === JSON.stringify(object3));
_x000D_
_x000D_
_x000D_


Are you trying to test if two objects are the equal? ie: their properties are equal?

If this is the case, you'll probably have noticed this situation:

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

you might have to do something like this:

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.


I'm making the following assumptions with this function:

  1. You control the objects you are comparing and you only have primitive values (ie. not nested objects, functions, etc.).
  2. Your browser has support for Object.keys.

This should be treated as a demonstration of a simple strategy.

/**
 * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
 * @param {Object} object1
 * @param {Object} object2
 * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
 * @returns {Boolean}
 */
function isEqual( object1, object2, order_matters ) {
    var keys1 = Object.keys(object1),
        keys2 = Object.keys(object2),
        i, key;

    // Test 1: Same number of elements
    if( keys1.length != keys2.length ) {
        return false;
    }

    // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
    // keys1 = Object.keys({a:2, b:1}) = ["a","b"];
    // keys2 = Object.keys({b:1, a:2}) = ["b","a"];
    // This is why we are sorting keys1 and keys2.
    if( !order_matters ) {
        keys1.sort();
        keys2.sort();
    }

    // Test 2: Same keys
    for( i = 0; i < keys1.length; i++ ) {
        if( keys1[i] != keys2[i] ) {
            return false;
        }
    }

    // Test 3: Values
    for( i = 0; i < keys1.length; i++ ) {
        key = keys1[i];
        if( object1[key] != object2[key] ) {
            return false;
        }
    }

    return true;
}

_x000D_
_x000D_
const obj = {
  name: "Carl",
  age: 15
}
const obj2 = {
  name: "Carl",
  age: 15,
}


const compareObj = (objects) => {
  const res =  objects.map((item) => {
    return Object.entries(item).flat().join()
  })
  return res.every((a) => {
    return a === res[0]
  })
}

console.log(compareObj([obj,obj2]))
_x000D_
_x000D_
_x000D_


This question has more than 30 answers already. I am going to summarize and explain them (with a "my father" analogy) and add my suggested solution.

You have 4+1 classes of solutions:


1) Use a hacky incomplete quick one-liner

Good if you are in a rush and 99% correctness works.

Examples of this is, JSON.stringify() suggested by Pratik Bhalodiya, or JSON.encode by Joel Anair, or .toString(), or other methods that transform your objects into a String and then compare the two Strings using === character by character.

The drawback, however, is that there is no globally standard unique representation of an Object in String. e.g. { a: 5, b: 8} and {b: 8 and a: 5 } are equal.

  • Pros: Fast, quick.
  • Cons: Hopefully works! It will not work if the environment/browser/engine memorizes the ordering for objects (e.g. Chrome/V8) and the order of the keys are different (Thanks to Eksapsy.) So, not guaranteed at all. Performance wouldn't be great either in large objects.

My Father Analogy

When I am talking about my father, "my tall handsome father" and "my handsome tall father" are the same person! But the two strings are not the same.

Note that there is actually a correct (standard way) order of adjectives in English grammar, which says it should be a "handsome tall man," but you are risking your competency if you blindly assume Javascript engine of iOS 8 Safari is also abiding the same grammar, blindly! #WelcomeToJavascriptNonStandards


2) Write your own DIY recursive function

Good if you are learning.

Examples are atmin's solution.

The biggest disadvantage is you will definitely miss some edge cases. Have you considered a self-reference in object values? Have you considered NaN? Have you considered two objects that have the same ownProperties but different prototypical parents?

I would only encourage people to do this if they are practicing and the code is not going to go in production. That's the only case that reinventing the wheel has justifications.

  • Pros: Learning opportunity.
  • Cons: Not reliable. Takes time and concerns.

My Father Analogy

It's like assuming if my dad's name is "John Smith" and his birthday is "1/1/1970", then anyone whose name is "John Smith" and is born on "1/1/1970" is my father.

That's usually the case, but what if there are two "John Smith"s born on that day? If you think you will consider their height, then that's increasing the accuracy but still not a perfect comparison.

2.1 You limited scope DIY comparator

Rather than going on a wild chase of checking all the properties recursively, one might consider checking only "a limited" number of properties. For instance, if the objects are Users, you can compare their emailAddress field.

It's still not a perfect one, but the benefits over solution #2 are:

  1. It's predictable, and it's less likely to crash.
  2. You are driving the "definition" of equality, rather than relying on a wild form and shape of the Object and its prototype and nested properties.

3) Use a library version of equal function

Good if you need a production-level quality, and you cannot change the design of the system.

Examples are _.equal of lodash, already in coolaj86's answer or Angular's or Ember's as mentioned in Tony Harvey's answer or Node's by Rafael Xavier.

  • Pros: It's what everyone else does.
  • Cons: External dependency, which can cost you extra memory/CPU/Security concerns, even a little bit. Also, can still miss some edge cases (e.g. whether two objects having same ownProperties but different prototypical parents should be considered the same or not.) Finally, you might be unintentionally band-aiding an underlying design problem with this; just saying!

My Father Analogy

It's like paying an agency to find my biological father, based on his phone, name, address, etc.

It's gonna cost more, and it's probably more accurate than myself running the background check, but doesn't cover edge cases like when my father is immigrant/asylum and his birthday is unknown!


4) Use an IDentifier in the Object

Good if you [still] can change the design of the system (objects you are dealing with) and you want your code to last long.

It's not applicable in all cases, and might not be very performant. However, it's a very reliable solution, if you can make it.

The solution is, every object in the system will have a unique identifier along with all the other properties. The uniqueness of the identifier will be guaranteed at the time of generation. And you will use this ID (also known as UUID/GUID -- Globally/Universally Unique Identifier) when it comes to comparing two objects. i.e. They are equal if and only if these IDs are equal.

The IDs can be simple auto_incremental numbers, or a string generated via a library (advised) or a piece of code. All you need to do is make sure it's always unique, which in case of auto_incremental it can be built-in, or in case of UUID, can be checked will all existing values (e.g. MySQL's UNIQUE column attribute) or simply (if coming from a library) be relied upon giving the extremely low likelihood of a collision.

Note that you also need to store the ID with the object at all times (to guarantee its uniqueness), and computing it in real-time might not be the best approach.

  • Pros: Reliable, efficient, not dirty, modern.
  • Cons: Needs extra space. Might need a redesign of the system.

My Father Analogy

It's like known my father's Social Security Number is 911-345-9283, so anyone who has this SSN is my father, and anyone who claims to be my father must have this SSN.


Conclusion

I personally prefer solution #4 (ID) over them all for accuracy and reliability. If it's not possible I'd go with #2.1 for predictability, and then #3. If neither is possible, #2 and finally #1.


My version, which includes the chain of where the difference is found, and what the difference is.

function DeepObjectCompare(O1, O2)
{
    try {
        DOC_Val(O1, O2, ['O1->O2', O1, O2]);
        return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
    } catch(e) {
        console.log(e.Chain);
        throw(e);
    }
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
    this.Reason=Reason;
    this.Chain=Chain;
    this.Val1=Val1;
    this.Val2=Val2;
}

function DOC_Val(Val1, Val2, Chain)
{
    function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }

    if(typeof(Val1)!==typeof(Val2))
        return DoThrow('Type Mismatch');
    if(Val1===null || Val1===undefined)
        return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
    if(Val1.constructor!==Val2.constructor)
        return DoThrow('Constructor mismatch');
    switch(typeof(Val1))
    {
        case 'object':
            for(var m in Val1)
            {
                if(!Val1.hasOwnProperty(m))
                    continue;
                var CurChain=Chain.concat([m]);
                if(!Val2.hasOwnProperty(m))
                    return DoThrow('Val2 missing property', CurChain);
                DOC_Val(Val1[m], Val2[m], CurChain);
            }
            return true;
        case 'number':
            if(Number.isNaN(Val1))
                return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
        case 'string':
        case 'boolean':
            return Val1!==Val2 ? DoThrow('Value mismatch') : true;
        case 'function':
            if(Val1.prototype!==Val2.prototype)
                return DoThrow('Prototype mismatch');
            if(Val1!==Val2)
                return DoThrow('Function mismatch');
            return true;
        default:
            return DoThrow('Val1 is unknown type');
    }
}

you can use _.isEqual(obj1, obj2) from the underscore.js library.

Here is an example:

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

See the official documentation from here: http://underscorejs.org/#isEqual


After so much of searches, i have found following working solution

function isEquivalent(a, b) {
   // Create arrays of property names
   var aProps = Object.getOwnPropertyNames(a);
   var bProps = Object.getOwnPropertyNames(b);

  // If number of properties is different, objects are not equivalent
  if (aProps.length != bProps.length) {
     return false;
  }

  for (var i = 0; i < aProps.length; i++) {
     var propName = aProps[i];

    // If values of same property are not equal, objects are not equivalent
     if (a[propName] !== b[propName]) {
         return false;
     }
  }

// If we made it this far, objects are considered equivalent
return true; }

For more info: Object Equality in JavaScript


I faced the same problem and deccided to write my own solution. But because I want to also compare Arrays with Objects and vice-versa, I crafted a generic solution. I decided to add the functions to the prototype, but one can easily rewrite them to standalone functions. Here is the code:

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

This Algorithm is split into two parts; The equals function itself and a function to find the numeric index of a property in an array / object. The find function is only needed because indexof only finds numbers and strings and no objects .

One can call it like this:

({a: 1, b: "h"}).equals({a: 1, b: "h"});

The function either returns true or false, in this case true. The algorithm als allows comparison between very complex objects:

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

The upper example will return true, even tho the properties have a different ordering. One small detail to look out for: This code also checks for the same type of two variables, so "3" is not the same as 3.


I have a much shorter function that will go deep into all sub objects or arrays. It is as efficient as JSON.stringify(obj1) === JSON.stringify(obj2) but JSON.stringify will not work if the order is not the same (as mentioned here).

var obj1 = { a : 1, b : 2 };
var obj2 = { b : 2, a : 1 };

console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false

The function would also be a good start if you want to do something with the unequal values.

_x000D_
_x000D_
function arr_or_obj(v)_x000D_
{ return !!v && (v.constructor === Object || v.constructor === Array); }_x000D_
_x000D_
function deep_equal(v1, v2)_x000D_
{_x000D_
    if (arr_or_obj(v1) && arr_or_obj(v2) && v1.constructor === v2.constructor)_x000D_
    {_x000D_
        if (Object.keys(v1).length === Object.keys(v2).length) // check the length_x000D_
        for (var i in v1)_x000D_
        {_x000D_
            if (!deep_equal(v1[i], v2[i]))_x000D_
            { return false; }_x000D_
        }_x000D_
        else_x000D_
        { return false; }_x000D_
    }_x000D_
    else if (v1 !== v2)_x000D_
    { return false; }_x000D_
_x000D_
    return true;_x000D_
}_x000D_
_x000D_
//////////////////////////////////////////////////////////////////_x000D_
//////////////////////////////////////////////////////////////////_x000D_
_x000D_
var obj1 = [_x000D_
    {_x000D_
        hat : {_x000D_
            cap : ['something', null ],_x000D_
            helmet : [ 'triple eight', 'pro-tec' ]_x000D_
        },_x000D_
        shoes : [ 'loafer', 'penny' ]_x000D_
    },_x000D_
    {_x000D_
        beers : [ 'budweiser', 'busch' ],_x000D_
        wines : [ 'barefoot', 'yellow tail' ]_x000D_
    }_x000D_
];_x000D_
_x000D_
var obj2 = [_x000D_
    {_x000D_
        shoes : [ 'loafer', 'penny' ], // same even if the order is different_x000D_
        hat : {_x000D_
            cap : ['something', null ],_x000D_
            helmet : [ 'triple eight', 'pro-tec' ]_x000D_
        }_x000D_
    },_x000D_
    {_x000D_
        beers : [ 'budweiser', 'busch' ],_x000D_
        wines : [ 'barefoot', 'yellow tail' ]_x000D_
    }_x000D_
];_x000D_
_x000D_
console.log(deep_equal(obj1, obj2)); // true_x000D_
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false_x000D_
console.log(deep_equal([], [])); // true_x000D_
console.log(deep_equal({}, {})); // true_x000D_
console.log(deep_equal([], {})); // false
_x000D_
_x000D_
_x000D_

And if you want to add support for Function, Date and RegExp, you can add this at the beginning of deep_equal (not tested):

if ((typeof obj1 === 'function' && typeof obj2 === 'function') ||
(obj1 instanceof Date && obj2 instanceof Date) ||
(obj1 instanceof RegExp && obj2 instanceof RegExp))
{
    obj1 = obj1.toString();
    obj2 = obj2.toString();
}

Depending. If the order of keys in the object are not of importance, and I don't need to know the prototypes of the said object. Using always do the job.

const object = {};
JSON.stringify(object) === "{}" will pass but {} === "{}" will not

I don't know if anyone's posted anything similar to this, but here's a function I made to check for object equalities.

function objectsAreEqual(a, b) {
  for (var prop in a) {
    if (a.hasOwnProperty(prop)) {
      if (b.hasOwnProperty(prop)) {
        if (typeof a[prop] === 'object') {
          if (!objectsAreEqual(a[prop], b[prop])) return false;
        } else {
          if (a[prop] !== b[prop]) return false;
        }
      } else {
        return false;
      }
    }
  }
  return true;
}

Also, it's recursive, so it can also check for deep equality, if that's what you call it.


Pulling out from my personal library, which i use for my work repeatedly. The following function is a lenient recursive deep equal, which does not check

  • Class equality
  • Inherited values
  • Values strict equality

I mainly use this to check if i get equal replies against various API implementation. Where implementation difference (like string vs number) and additional null values, can occur.

Its implementation is quite straightforward and short (if all the comments is stripped off)

_x000D_
_x000D_
/** Recursively check if both objects are equal in value_x000D_
***_x000D_
*** This function is designed to use multiple methods from most probable _x000D_
*** (and in most cases) valid, to the more regid and complex method._x000D_
***_x000D_
*** One of the main principles behind the various check is that while_x000D_
*** some of the simpler checks such as == or JSON may cause false negatives,_x000D_
*** they do not cause false positives. As such they can be safely run first._x000D_
***_x000D_
*** # !Important Note:_x000D_
*** as this function is designed for simplified deep equal checks it is not designed_x000D_
*** for the following_x000D_
***_x000D_
*** - Class equality, (ClassA().a = 1) maybe valid to (ClassB().b = 1)_x000D_
*** - Inherited values, this actually ignores them_x000D_
*** - Values being strictly equal, "1" is equal to 1 (see the basic equality check on this)_x000D_
*** - Performance across all cases. This is designed for high performance on the_x000D_
***   most probable cases of == / JSON equality. Consider bench testing, if you have_x000D_
***   more 'complex' requirments_x000D_
***_x000D_
*** @param  objA : First object to compare_x000D_
*** @param  objB : 2nd object to compare_x000D_
*** @param  .... : Any other objects to compare_x000D_
***_x000D_
*** @returns true if all equals, or false if invalid_x000D_
***_x000D_
*** @license Copyright by [email protected], 2012._x000D_
***          Licensed under the MIT license: http://opensource.org/licenses/MIT_x000D_
**/_x000D_
function simpleRecusiveDeepEqual(objA, objB) {_x000D_
 // Multiple comparision check_x000D_
 //--------------------------------------------_x000D_
 var args = Array.prototype.slice.call(arguments);_x000D_
 if(args.length > 2) {_x000D_
  for(var a=1; a<args.length; ++a) {_x000D_
   if(!simpleRecusiveDeepEqual(args[a-1], args[a])) {_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
  return true;_x000D_
 } else if(args.length < 2) {_x000D_
  throw "simpleRecusiveDeepEqual, requires atleast 2 arguments";_x000D_
 }_x000D_
 _x000D_
 // basic equality check,_x000D_
 //--------------------------------------------_x000D_
 // if this succed the 2 basic values is equal,_x000D_
 // such as numbers and string._x000D_
 //_x000D_
 // or its actually the same object pointer. Bam_x000D_
 //_x000D_
 // Note that if string and number strictly equal is required_x000D_
 // change the equality from ==, to ===_x000D_
 //_x000D_
 if(objA == objB) {_x000D_
  return true;_x000D_
 }_x000D_
 _x000D_
 // If a value is a bsic type, and failed above. This fails_x000D_
 var basicTypes = ["boolean", "number", "string"];_x000D_
 if( basicTypes.indexOf(typeof objA) >= 0 || basicTypes.indexOf(typeof objB) >= 0 ) {_x000D_
  return false;_x000D_
 }_x000D_
 _x000D_
 // JSON equality check,_x000D_
 //--------------------------------------------_x000D_
 // this can fail, if the JSON stringify the objects in the wrong order_x000D_
 // for example the following may fail, due to different string order:_x000D_
 //_x000D_
 // JSON.stringify( {a:1, b:2} ) == JSON.stringify( {b:2, a:1} )_x000D_
 //_x000D_
 if(JSON.stringify(objA) == JSON.stringify(objB)) {_x000D_
  return true;_x000D_
 }_x000D_
 _x000D_
 // Array equality check_x000D_
 //--------------------------------------------_x000D_
 // This is performed prior to iteration check,_x000D_
 // Without this check the following would have been considered valid_x000D_
 //_x000D_
 // simpleRecusiveDeepEqual( { 0:1963 }, [1963] );_x000D_
 //_x000D_
 // Note that u may remove this segment if this is what is intended_x000D_
 //_x000D_
 if( Array.isArray(objA) ) {_x000D_
  //objA is array, objB is not an array_x000D_
  if( !Array.isArray(objB) ) {_x000D_
   return false;_x000D_
  }_x000D_
 } else if( Array.isArray(objB) ) {_x000D_
  //objA is not array, objB is an array_x000D_
  return false;_x000D_
 }_x000D_
 _x000D_
 // Nested values iteration_x000D_
 //--------------------------------------------_x000D_
 // Scan and iterate all the nested values, and check for non equal values recusively_x000D_
 //_x000D_
 // Note that this does not check against null equality, remove the various "!= null"_x000D_
 // if this is required_x000D_
 _x000D_
 var i; //reuse var to iterate_x000D_
 _x000D_
 // Check objA values against objB_x000D_
 for (i in objA) {_x000D_
  //Protect against inherited properties_x000D_
  if(objA.hasOwnProperty(i)) {_x000D_
   if(objB.hasOwnProperty(i)) {_x000D_
    // Check if deep equal is valid_x000D_
    if(!simpleRecusiveDeepEqual( objA[i], objB[i] )) {_x000D_
     return false;_x000D_
    }_x000D_
   } else if(objA[i] != null) {_x000D_
    //ignore null values in objA, that objB does not have_x000D_
    //else fails_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
 }_x000D_
 _x000D_
 // Check if objB has additional values, that objA do not, fail if so_x000D_
 for (i in objB) {_x000D_
  if(objB.hasOwnProperty(i)) {_x000D_
   if(objB[i] != null && !objA.hasOwnProperty(i)) {_x000D_
    //ignore null values in objB, that objA does not have_x000D_
    //else fails_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
 }_x000D_
 _x000D_
 // End of all checks_x000D_
 //--------------------------------------------_x000D_
 // By reaching here, all iteration scans have been done._x000D_
 // and should have returned false if it failed_x000D_
 return true;_x000D_
}_x000D_
_x000D_
// Sanity checking of simpleRecusiveDeepEqual_x000D_
(function() {_x000D_
 if(_x000D_
  // Basic checks_x000D_
  !simpleRecusiveDeepEqual({}, {}) ||_x000D_
  !simpleRecusiveDeepEqual([], []) ||_x000D_
  !simpleRecusiveDeepEqual(['a'], ['a']) ||_x000D_
  // Not strict checks_x000D_
  !simpleRecusiveDeepEqual("1", 1) ||_x000D_
  // Multiple objects check_x000D_
  !simpleRecusiveDeepEqual( { a:[1,2] }, { a:[1,2] }, { a:[1,2] } ) ||_x000D_
  // Ensure distinction between array and object (the following should fail)_x000D_
  simpleRecusiveDeepEqual( [1963], { 0:1963 } ) ||_x000D_
  // Null strict checks_x000D_
  simpleRecusiveDeepEqual( 0, null ) ||_x000D_
  simpleRecusiveDeepEqual( "", null ) ||_x000D_
  // Last "false" exists to make the various check above easy to comment in/out_x000D_
  false_x000D_
 ) {_x000D_
  alert("FATAL ERROR: simpleRecusiveDeepEqual failed basic checks");_x000D_
 } else { _x000D_
  //added this last line, for SO snippet alert on success_x000D_
  alert("simpleRecusiveDeepEqual: Passed all checks, Yays!");_x000D_
 }_x000D_
})();
_x000D_
_x000D_
_x000D_


I've implemented a method that takes two jsons and checks to see if their keys have the same values using recursion. I used another question to solve this.

_x000D_
_x000D_
const arraysEqual = (a, b) => {_x000D_
    if (a === b)_x000D_
        return true;_x000D_
    if (a === null || b === null)_x000D_
        return false;_x000D_
    if (a.length !== b.length)_x000D_
        return false;_x000D_
_x000D_
    // If you don't care about the order of the elements inside_x000D_
    // the array, you should sort both arrays here._x000D_
_x000D_
    for (let i = 0; i < a.length; ++i) {_x000D_
        if (a[i] !== b[i])_x000D_
            return false;_x000D_
    }_x000D_
    return true;_x000D_
};_x000D_
_x000D_
const jsonsEqual = (a, b) => {_x000D_
_x000D_
  if(typeof a !== 'object' || typeof b !== 'object')_x000D_
      return false;_x000D_
_x000D_
  if (Object.keys(a).length === Object.keys(b).length) { // if items have the same size_x000D_
      let response = true;_x000D_
_x000D_
      for (let key in a) {_x000D_
          if (!b[key]) // if not key_x000D_
              response = false;_x000D_
          if (typeof a[key] !== typeof b[key]) // if typeof doesn't equals_x000D_
              response = false;_x000D_
          else {_x000D_
              if (Array.isArray(a[key])) // if array_x000D_
                  response = arraysEqual(a[key], b[key]);_x000D_
              else if (typeof a[key] === 'object') // if another json_x000D_
                  response = jsonsEqual(a[key], b[key]);_x000D_
              else if (a[key] !== b[key])  // not equals_x000D_
                  response = false;_x000D_
          }_x000D_
          if (!response) // return if one item isn't equal_x000D_
              return false;_x000D_
      }_x000D_
  } else_x000D_
      return false;_x000D_
_x000D_
  return true;_x000D_
};_x000D_
_x000D_
const json1 = { _x000D_
  a: 'a', _x000D_
  b: 'asd', _x000D_
  c: [_x000D_
    '1',_x000D_
    2,_x000D_
    2.5,_x000D_
    '3', _x000D_
    {_x000D_
      d: 'asd',_x000D_
      e: [_x000D_
        1.6,_x000D_
        { _x000D_
          f: 'asdasd',_x000D_
          g: '123'_x000D_
        }_x000D_
      ]_x000D_
    }_x000D_
  ],_x000D_
  h: 1,_x000D_
  i: 1.2,_x000D_
};_x000D_
_x000D_
const json2 = {_x000D_
  a: 'nops',_x000D_
  b: 'asd'_x000D_
};_x000D_
_x000D_
const json3 = { _x000D_
  a: 'h', _x000D_
  b: '484', _x000D_
  c: [_x000D_
    3,_x000D_
    4.5,_x000D_
    '2ss', _x000D_
    {_x000D_
      e: [_x000D_
        { _x000D_
          f: 'asdasd',_x000D_
          g: '123'_x000D_
        }_x000D_
      ]_x000D_
    }_x000D_
  ],_x000D_
  h: 1,_x000D_
  i: 1.2,_x000D_
};_x000D_
_x000D_
const result = jsonsEqual(json1,json2);_x000D_
//const result = jsonsEqual(json1,json3);_x000D_
//const result = jsonsEqual(json1,json1);_x000D_
_x000D_
if(result) // is equal_x000D_
  $('#result').text("Jsons are the same")_x000D_
else_x000D_
  $('#result').text("Jsons aren't equals")
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
_x000D_
<div id="result"></div>
_x000D_
_x000D_
_x000D_


Depending. If the order of keys in the object are not of importance, and I don't need to know the prototypes of the said object. Using always do the job.

const object = {};
JSON.stringify(object) === "{}" will pass but {} === "{}" will not

Here is generic equality checker function that receives array of elements as input and compare them to each other. Works with all types of elements.

const isEqual = function(inputs = []) {
  // Checks an element if js object.
  const isObject = function(data) {
    return Object.prototype.toString.call(data) === '[object Object]';
  };
  // Sorts given object by its keys.
  const sortObjectByKey = function(obj) {
    const self = this;
    if (!obj) return {};
    return Object.keys(obj).sort().reduce((initialVal, item) => {
      initialVal[item] = !Array.isArray(obj[item]) &&
        typeof obj[item] === 'object'
        ? self.objectByKey(obj[item])
        : obj[item];
      return initialVal;
    }, {});
  };

  // Checks equality of all elements in the input against each other. Returns true | false
  return (
    inputs
      .map(
        input =>
          typeof input == 'undefined'
            ? ''
            : isObject(input)
                ? JSON.stringify(sortObjectByKey(input))
                : JSON.stringify(input)
      )
      .reduce(
        (prevValue, input) =>
          prevValue === '' || prevValue === input ? input : false,
        ''
      ) !== false
  );
};

// Tests (Made with Jest test framework.)
test('String equality check', () => {
  expect(isEqual(['murat'])).toEqual(true);
  expect(isEqual(['murat', 'john', 'doe'])).toEqual(false);
  expect(isEqual(['murat', 'murat', 'murat'])).toEqual(true);
});

test('Float equality check', () => {
  expect(isEqual([7.89, 3.45])).toEqual(false);
  expect(isEqual([7, 7.50])).toEqual(false);
  expect(isEqual([7.50, 7.50])).toEqual(true);
  expect(isEqual([7, 7])).toEqual(true);
  expect(isEqual([0.34, 0.33])).toEqual(false);
  expect(isEqual([0.33, 0.33])).toEqual(true);
});

test('Array equality check', () => {
  expect(isEqual([[1, 2, 3], [1, 2, 3]])).toEqual(true);
  expect(isEqual([[1, 3], [1, 2, 3]])).toEqual(false);
  expect(isEqual([['murat', 18], ['murat', 18]])).toEqual(true);
});

test('Object equality check', () => {
  let obj1 = {
    name: 'murat',
    age: 18
  };
  let obj2 = {
    name: 'murat',
    age: 18
  };
  let obj3 = {
    age: 18,
    name: 'murat'
  };
  let obj4 = {
    name: 'murat',
    age: 18,
    occupation: 'nothing'
  };
  expect(isEqual([obj1, obj2])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3, obj4])).toEqual(false);
});

test('Weird equality checks', () => {
  expect(isEqual(['', {}])).toEqual(false);
  expect(isEqual([0, '0'])).toEqual(false);
});

There is also a gist


function isEqual(obj1, obj2){
    type1 = typeof(obj1);
    type2 = typeof(obj2);
    if(type1===type2){
        switch (type1){
            case "object": return JSON.stringify(obj1)===JSON.stringify(obj2);
            case "function": return eval(obj1).toString()===eval(obj2).toString();
            default: return obj1==obj2;
        }
    }
    return false;
}//have not tried but should work.

Heres's a solution in ES6/ES2015 using a functional-style approach:

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

demo available here


ES6: The minimum code I could get it done, is this. It do deep comparison recursively by stringifying all key value array sorted representing the object, the only limitation is no methods or symbols are compare.

_x000D_
_x000D_
const compareObjects = (a, b) => { 
  let s = (o) => Object.entries(o).sort().map(i => { 
     if(i[1] instanceof Object) i[1] = s(i[1]);
     return i 
  }) 
  return JSON.stringify(s(a)) === JSON.stringify(s(b))
}

console.log(compareObjects({b:4,a:{b:1}}, {a:{b:1},b:4}));
_x000D_
_x000D_
_x000D_

IMPORTANT: This function is doing a JSON.stringfy in an ARRAY with the keys sorted and NOT in the object it self:

  1. ["a", ["b", 1]]
  2. ["b", 4]

Here is a very basic approach to checking an object's "value equality".

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

function isEquivalent(a, b) {
    // Create arrays of property names

    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different, objects are not equivalent

    if (aProps.length != bProps.length) {
        return false;
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];

        // If values of same property are not equal, objects are not equivalent
        if (a[propName] !== b[propName]) {
           return false;
        }
    }

    // If we made it this far, objects are considered equivalent
    return true;
}

// Outputs: true
console.log(isEquivalent(john, bobby));

Demo - JSFiddle

As you can see, to check the objects' "value equality" we essentially have to iterate over every property in the objects to see whether they are equal. And while this simple implementation works for our example, there are a lot of cases that it doesn't handle. For instance:

  • What if one of the property values is itself an object?
  • What if one of the property values is NaN (the only value in JavaScript that is not equal to itself?)
  • What if a has a property with value undefined, while b doesn't have this property (which thus evaluates to undefined?)

For a robust method of checking objects' "value equality" it is better to rely on a well-tested library that covers the various edge cases like Underscore.

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

// Outputs: true
console.log(_.isEqual(john, bobby));

Demo - JSFiddle


If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.


How to determine that the partial object (Partial<T>) is equal to the original object (T) in typescript.

function compareTwoObjects<T>(original: T, partial: Partial<T>): boolean {
  return !Object.keys(partial).some((key) => partial[key] !== original[key]);
}

P.S. Initially I was planning to create a new question with an answer. But such a question already exists and marked as a duplicate.


Are you trying to test if two objects are the equal? ie: their properties are equal?

If this is the case, you'll probably have noticed this situation:

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

you might have to do something like this:

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.


I've written a small library that runs on Node.js and the browser called compare.js. It offers the usual comparison operators, such as ==, !=, >, >=, <, <= and identity on all data types of JavaScript.

E.g., you can use

cmp.eq(obj1, obj2);

and this will check for equality (using a deep-equal approach). Otherwise, if you do

cmp.id(obj1, obj2);

it will compare by reference, hence check for identity. You can also use < and > on objects, which mean subset and superset.

compare.js is covered by nearly 700 unit tests, hence it should hopefully not have too many bugs ;-).

You can find it on https://github.com/goloroden/compare.js for free, it is open-sourced under the MIT license.


Here is generic equality checker function that receives array of elements as input and compare them to each other. Works with all types of elements.

const isEqual = function(inputs = []) {
  // Checks an element if js object.
  const isObject = function(data) {
    return Object.prototype.toString.call(data) === '[object Object]';
  };
  // Sorts given object by its keys.
  const sortObjectByKey = function(obj) {
    const self = this;
    if (!obj) return {};
    return Object.keys(obj).sort().reduce((initialVal, item) => {
      initialVal[item] = !Array.isArray(obj[item]) &&
        typeof obj[item] === 'object'
        ? self.objectByKey(obj[item])
        : obj[item];
      return initialVal;
    }, {});
  };

  // Checks equality of all elements in the input against each other. Returns true | false
  return (
    inputs
      .map(
        input =>
          typeof input == 'undefined'
            ? ''
            : isObject(input)
                ? JSON.stringify(sortObjectByKey(input))
                : JSON.stringify(input)
      )
      .reduce(
        (prevValue, input) =>
          prevValue === '' || prevValue === input ? input : false,
        ''
      ) !== false
  );
};

// Tests (Made with Jest test framework.)
test('String equality check', () => {
  expect(isEqual(['murat'])).toEqual(true);
  expect(isEqual(['murat', 'john', 'doe'])).toEqual(false);
  expect(isEqual(['murat', 'murat', 'murat'])).toEqual(true);
});

test('Float equality check', () => {
  expect(isEqual([7.89, 3.45])).toEqual(false);
  expect(isEqual([7, 7.50])).toEqual(false);
  expect(isEqual([7.50, 7.50])).toEqual(true);
  expect(isEqual([7, 7])).toEqual(true);
  expect(isEqual([0.34, 0.33])).toEqual(false);
  expect(isEqual([0.33, 0.33])).toEqual(true);
});

test('Array equality check', () => {
  expect(isEqual([[1, 2, 3], [1, 2, 3]])).toEqual(true);
  expect(isEqual([[1, 3], [1, 2, 3]])).toEqual(false);
  expect(isEqual([['murat', 18], ['murat', 18]])).toEqual(true);
});

test('Object equality check', () => {
  let obj1 = {
    name: 'murat',
    age: 18
  };
  let obj2 = {
    name: 'murat',
    age: 18
  };
  let obj3 = {
    age: 18,
    name: 'murat'
  };
  let obj4 = {
    name: 'murat',
    age: 18,
    occupation: 'nothing'
  };
  expect(isEqual([obj1, obj2])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3])).toEqual(true);
  expect(isEqual([obj1, obj2, obj3, obj4])).toEqual(false);
});

test('Weird equality checks', () => {
  expect(isEqual(['', {}])).toEqual(false);
  expect(isEqual([0, '0'])).toEqual(false);
});

There is also a gist


Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).


I don't know if anyone's posted anything similar to this, but here's a function I made to check for object equalities.

function objectsAreEqual(a, b) {
  for (var prop in a) {
    if (a.hasOwnProperty(prop)) {
      if (b.hasOwnProperty(prop)) {
        if (typeof a[prop] === 'object') {
          if (!objectsAreEqual(a[prop], b[prop])) return false;
        } else {
          if (a[prop] !== b[prop]) return false;
        }
      } else {
        return false;
      }
    }
  }
  return true;
}

Also, it's recursive, so it can also check for deep equality, if that's what you call it.


_x000D_
_x000D_
function isDeepEqual(obj1, obj2, testPrototypes = false) {_x000D_
  if (obj1 === obj2) {_x000D_
    return true_x000D_
  }_x000D_
_x000D_
  if (typeof obj1 === "function" && typeof obj2 === "function") {_x000D_
    return obj1.toString() === obj2.toString()_x000D_
  }_x000D_
_x000D_
  if (obj1 instanceof Date && obj2 instanceof Date) {_x000D_
    return obj1.getTime() === obj2.getTime()_x000D_
  }_x000D_
_x000D_
  if (_x000D_
    Object.prototype.toString.call(obj1) !==_x000D_
      Object.prototype.toString.call(obj2) ||_x000D_
    typeof obj1 !== "object"_x000D_
  ) {_x000D_
    return false_x000D_
  }_x000D_
_x000D_
  const prototypesAreEqual = testPrototypes_x000D_
    ? isDeepEqual(_x000D_
        Object.getPrototypeOf(obj1),_x000D_
        Object.getPrototypeOf(obj2),_x000D_
        true_x000D_
      )_x000D_
    : true_x000D_
_x000D_
  const obj1Props = Object.getOwnPropertyNames(obj1)_x000D_
  const obj2Props = Object.getOwnPropertyNames(obj2)_x000D_
_x000D_
  return (_x000D_
    obj1Props.length === obj2Props.length &&_x000D_
    prototypesAreEqual &&_x000D_
    obj1Props.every(prop => isDeepEqual(obj1[prop], obj2[prop]))_x000D_
  )_x000D_
}_x000D_
_x000D_
console.log(isDeepEqual({key: 'one'}, {key: 'first'}))_x000D_
console.log(isDeepEqual({key: 'one'}, {key: 'one'}))
_x000D_
_x000D_
_x000D_


For comparing keys for simple key/value pairs object instances, I use:

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

Once keys are compared, a simple additional for..in loop is enough.

Complexity is O(N*N) with N is the number of keys.

I hope/guess objects I define won't hold more than 1000 properties...


I'd advise against hashing or serialization (as the JSON solution suggest). If you need to test if two objects are equal, then you need to define what equals means. It could be that all data members in both objects match, or it could be that must the memory locations match (meaning both variables reference the same object in memory), or may be that only one data member in each object must match.

Recently I developed an object whose constructor creates a new id (starting from 1 and incrementing by 1) each time an instance is created. This object has an isEqual function that compares that id value with the id value of another object and returns true if they match.

In that case I defined "equal" as meaning the the id values match. Given that each instance has a unique id this could be used to enforce the idea that matching objects also occupy the same memory location. Although that is not necessary.


I need to mock jQuery POST requests, so the equality that matters to me is that both objects have the same set of properties (none missing in either object), and that each property value is "equal" (according to this definition). I don't care about the objects having mismatching methods.

Here's what I'll be using, it should be good enough for my specific requirements:

function PostRequest() {
    for (var i = 0; i < arguments.length; i += 2) {
        this[arguments[i]] = arguments[i+1];
    }

    var compare = function(u, v) {
        if (typeof(u) != typeof(v)) {
            return false;
        }

        var allkeys = {};
        for (var i in u) {
            allkeys[i] = 1;
        }
        for (var i in v) {
            allkeys[i] = 1;
        }
        for (var i in allkeys) {
            if (u.hasOwnProperty(i) != v.hasOwnProperty(i)) {
                if ((u.hasOwnProperty(i) && typeof(u[i]) == 'function') ||
                    (v.hasOwnProperty(i) && typeof(v[i]) == 'function')) {
                    continue;
                } else {
                    return false;
                }
            }
            if (typeof(u[i]) != typeof(v[i])) {
                return false;
            }
            if (typeof(u[i]) == 'object') {
                if (!compare(u[i], v[i])) {
                    return false;
                }
            } else {
                if (u[i] !== v[i]) {
                    return false;
                }
            }
        }

        return true;
    };

    this.equals = function(o) {
        return compare(this, o);
    };

    return this;
}

Use like so:

foo = new PostRequest('text', 'hello', 'html', '<p>hello</p>');
foo.equals({ html: '<p>hello</p>', text: 'hello' });

Yeah, another answer...

_x000D_
_x000D_
Object.prototype.equals = function (object) {_x000D_
    if (this.constructor !== object.constructor) return false;_x000D_
    if (Object.keys(this).length !== Object.keys(object).length) return false;_x000D_
    var obk;_x000D_
    for (obk in object) {_x000D_
        if (this[obk] !== object[obk])_x000D_
            return false;_x000D_
    }_x000D_
    return true;_x000D_
}_x000D_
_x000D_
var aaa = JSON.parse('{"name":"mike","tel":"1324356584"}');_x000D_
var bbb = JSON.parse('{"tel":"1324356584","name":"mike"}');_x000D_
var ccc = JSON.parse('{"name":"mike","tel":"584"}');_x000D_
var ddd = JSON.parse('{"name":"mike","tel":"1324356584", "work":"nope"}');_x000D_
_x000D_
$("#ab").text(aaa.equals(bbb));_x000D_
$("#ba").text(bbb.equals(aaa));_x000D_
$("#bc").text(bbb.equals(ccc));_x000D_
$("#ad").text(aaa.equals(ddd));
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
aaa equals bbb? <span id="ab"></span> <br/>_x000D_
bbb equals aaa? <span id="ba"></span> <br/>_x000D_
bbb equals ccc? <span id="bc"></span> <br/>_x000D_
aaa equals ddd? <span id="ad"></span>
_x000D_
_x000D_
_x000D_


const one={name:'mohit' , age:30};
//const two ={name:'mohit',age:30};
const two ={age:30,name:'mohit'};

function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);



// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
    return false;
}

for (var i = 0; i < aProps.length; i++) {
    var propName = aProps[i];

    // If values of same property are not equal,
    // objects are not equivalent
    if (a[propName] !== b[propName]) {
        return false;
    }
}

// If we made it this far, objects
// are considered equivalent
return true;
}

console.log(isEquivalent(one,two))

ES6: The minimum code I could get it done, is this. It do deep comparison recursively by stringifying all key value array sorted representing the object, the only limitation is no methods or symbols are compare.

_x000D_
_x000D_
const compareObjects = (a, b) => { 
  let s = (o) => Object.entries(o).sort().map(i => { 
     if(i[1] instanceof Object) i[1] = s(i[1]);
     return i 
  }) 
  return JSON.stringify(s(a)) === JSON.stringify(s(b))
}

console.log(compareObjects({b:4,a:{b:1}}, {a:{b:1},b:4}));
_x000D_
_x000D_
_x000D_

IMPORTANT: This function is doing a JSON.stringfy in an ARRAY with the keys sorted and NOT in the object it self:

  1. ["a", ["b", 1]]
  2. ["b", 4]

I just wrote this method just to be sure that arrays and objects are both compared in a clear way.

This should do the trick as well! :)

public class Objects {
    /**
     * Checks whether a value is of type Object
     * @param value the value
     */
    public static isObject = (value: any): boolean => {
        return value === Object(value) && Object.prototype.toString.call(value) !== '[object Array]'
    }

    /**
     * Checks whether a value is of type Array
     * @param value the value
     */
    public static isArray = (value: any): boolean => {
        return Object.prototype.toString.call(value) === '[object Array]' && !Objects.isObject(value)
    }

    /**
     * Check whether two values are equal
     */
    public static isEqual = (objectA: any, objectB: any) => {
        // Objects
        if (Objects.isObject(objectA) && !Objects.isObject(objectB)) {
            return false
        }
        else if (!Objects.isObject(objectA) && Objects.isObject(objectB)) {
            return false
        }
        // Arrays
        else if (Objects.isArray(objectA) && !Objects.isArray(objectB)) {
            return false
        }
        else if (!Objects.isArray(objectA) && Objects.isArray(objectB)) {
            return false
        }
        // Primitives
        else if (!Objects.isArray(objectA) && !Objects.isObject(objectA)) {
            return objectA === objectB
        }
        // Object or array
        else {
            const compareObject = (objectA: any, objectB: any): boolean => {
                if (Object.keys(objectA).length !== Object.keys(objectB).length) return false

                for (const propertyName of Object.keys(objectA)) {
                    const valueA = objectA[propertyName]
                    const valueB = objectB[propertyName]

                    if (!Objects.isEqual(valueA, valueB)) {
                        return false
                    }
                }

                return true
            }
            const compareArray = (arrayA: any[], arrayB: any[]): boolean => {
                if (arrayA.length !== arrayB.length) return false

                for (const index in arrayA) {
                    const valueA = arrayA[index]
                    const valueB = arrayB[index]

                    if (!Objects.isEqual(valueA, valueB)) {
                        return false
                    }
                }

                return true
            }
            if (Objects.isObject(objectA)) {
                return compareObject(objectA, objectB)
            } else {
                return compareArray(objectA, objectB)
            }
        }
    }
}

Though there are so many answers to this question already. My attempt is just to provide one more way of implementing this:

_x000D_
_x000D_
const primitveDataTypes = ['number', 'boolean', 'string', 'undefined'];_x000D_
const isDateOrRegExp = (value) => value instanceof Date || value instanceof RegExp;_x000D_
const compare = (first, second) => {_x000D_
    let agg = true;_x000D_
    if(typeof first === typeof second && primitveDataTypes.indexOf(typeof first) !== -1 && first !== second){_x000D_
        agg =  false;_x000D_
    }_x000D_
    // adding support for Date and RegExp._x000D_
    else if(isDateOrRegExp(first) || isDateOrRegExp(second)){_x000D_
        if(first.toString() !== second.toString()){_x000D_
            agg = false;_x000D_
        }_x000D_
    }_x000D_
    else {_x000D_
        if(Array.isArray(first) && Array.isArray(second)){_x000D_
        if(first.length === second.length){_x000D_
             for(let i = 0; i < first.length; i++){_x000D_
                if(typeof first[i] === 'object' && typeof second[i] === 'object'){_x000D_
                    agg = compare(first[i], second[i]);_x000D_
                }_x000D_
                else if(first[i] !== second[i]){_x000D_
                    agg = false;_x000D_
                }_x000D_
            }_x000D_
        } else {_x000D_
            agg = false;_x000D_
        }_x000D_
    } else {_x000D_
        const firstKeys = Object.keys(first);_x000D_
        const secondKeys = Object.keys(second);_x000D_
        if(firstKeys.length !== secondKeys.length){_x000D_
            agg = false;_x000D_
        }_x000D_
        for(let j = 0 ; j < firstKeys.length; j++){_x000D_
            if(firstKeys[j] !== secondKeys[j]){_x000D_
                agg = false;_x000D_
            }_x000D_
            if(first[firstKeys[j]] && second[secondKeys[j]] && typeof first[firstKeys[j]] === 'object' && typeof second[secondKeys[j]] === 'object'){_x000D_
                agg = compare(first[firstKeys[j]], second[secondKeys[j]]);_x000D_
             } _x000D_
             else if(first[firstKeys[j]] !== second[secondKeys[j]]){_x000D_
                agg = false;_x000D_
             } _x000D_
        }_x000D_
    }_x000D_
    }_x000D_
    return agg;_x000D_
}_x000D_
_x000D_
_x000D_
console.log('result', compare({a: 1, b: { c: [4, {d:5}, {e:6}]}, r: null}, {a: 1, b: { c: [4, {d:5}, {e:6}]}, r: 'ffd'}));  //returns false.
_x000D_
_x000D_
_x000D_


I know this is a bit old, but I would like to add a solution that I came up with for this problem. I had an object and I wanted to know when its data changed. "something similar to Object.observe" and what I did was:

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

This here can be duplicated and create an other set of arrays to compare the values and keys. It is very simple because they are now arrays and will return false if objects have different sizes.


Pulling out from my personal library, which i use for my work repeatedly. The following function is a lenient recursive deep equal, which does not check

  • Class equality
  • Inherited values
  • Values strict equality

I mainly use this to check if i get equal replies against various API implementation. Where implementation difference (like string vs number) and additional null values, can occur.

Its implementation is quite straightforward and short (if all the comments is stripped off)

_x000D_
_x000D_
/** Recursively check if both objects are equal in value_x000D_
***_x000D_
*** This function is designed to use multiple methods from most probable _x000D_
*** (and in most cases) valid, to the more regid and complex method._x000D_
***_x000D_
*** One of the main principles behind the various check is that while_x000D_
*** some of the simpler checks such as == or JSON may cause false negatives,_x000D_
*** they do not cause false positives. As such they can be safely run first._x000D_
***_x000D_
*** # !Important Note:_x000D_
*** as this function is designed for simplified deep equal checks it is not designed_x000D_
*** for the following_x000D_
***_x000D_
*** - Class equality, (ClassA().a = 1) maybe valid to (ClassB().b = 1)_x000D_
*** - Inherited values, this actually ignores them_x000D_
*** - Values being strictly equal, "1" is equal to 1 (see the basic equality check on this)_x000D_
*** - Performance across all cases. This is designed for high performance on the_x000D_
***   most probable cases of == / JSON equality. Consider bench testing, if you have_x000D_
***   more 'complex' requirments_x000D_
***_x000D_
*** @param  objA : First object to compare_x000D_
*** @param  objB : 2nd object to compare_x000D_
*** @param  .... : Any other objects to compare_x000D_
***_x000D_
*** @returns true if all equals, or false if invalid_x000D_
***_x000D_
*** @license Copyright by [email protected], 2012._x000D_
***          Licensed under the MIT license: http://opensource.org/licenses/MIT_x000D_
**/_x000D_
function simpleRecusiveDeepEqual(objA, objB) {_x000D_
 // Multiple comparision check_x000D_
 //--------------------------------------------_x000D_
 var args = Array.prototype.slice.call(arguments);_x000D_
 if(args.length > 2) {_x000D_
  for(var a=1; a<args.length; ++a) {_x000D_
   if(!simpleRecusiveDeepEqual(args[a-1], args[a])) {_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
  return true;_x000D_
 } else if(args.length < 2) {_x000D_
  throw "simpleRecusiveDeepEqual, requires atleast 2 arguments";_x000D_
 }_x000D_
 _x000D_
 // basic equality check,_x000D_
 //--------------------------------------------_x000D_
 // if this succed the 2 basic values is equal,_x000D_
 // such as numbers and string._x000D_
 //_x000D_
 // or its actually the same object pointer. Bam_x000D_
 //_x000D_
 // Note that if string and number strictly equal is required_x000D_
 // change the equality from ==, to ===_x000D_
 //_x000D_
 if(objA == objB) {_x000D_
  return true;_x000D_
 }_x000D_
 _x000D_
 // If a value is a bsic type, and failed above. This fails_x000D_
 var basicTypes = ["boolean", "number", "string"];_x000D_
 if( basicTypes.indexOf(typeof objA) >= 0 || basicTypes.indexOf(typeof objB) >= 0 ) {_x000D_
  return false;_x000D_
 }_x000D_
 _x000D_
 // JSON equality check,_x000D_
 //--------------------------------------------_x000D_
 // this can fail, if the JSON stringify the objects in the wrong order_x000D_
 // for example the following may fail, due to different string order:_x000D_
 //_x000D_
 // JSON.stringify( {a:1, b:2} ) == JSON.stringify( {b:2, a:1} )_x000D_
 //_x000D_
 if(JSON.stringify(objA) == JSON.stringify(objB)) {_x000D_
  return true;_x000D_
 }_x000D_
 _x000D_
 // Array equality check_x000D_
 //--------------------------------------------_x000D_
 // This is performed prior to iteration check,_x000D_
 // Without this check the following would have been considered valid_x000D_
 //_x000D_
 // simpleRecusiveDeepEqual( { 0:1963 }, [1963] );_x000D_
 //_x000D_
 // Note that u may remove this segment if this is what is intended_x000D_
 //_x000D_
 if( Array.isArray(objA) ) {_x000D_
  //objA is array, objB is not an array_x000D_
  if( !Array.isArray(objB) ) {_x000D_
   return false;_x000D_
  }_x000D_
 } else if( Array.isArray(objB) ) {_x000D_
  //objA is not array, objB is an array_x000D_
  return false;_x000D_
 }_x000D_
 _x000D_
 // Nested values iteration_x000D_
 //--------------------------------------------_x000D_
 // Scan and iterate all the nested values, and check for non equal values recusively_x000D_
 //_x000D_
 // Note that this does not check against null equality, remove the various "!= null"_x000D_
 // if this is required_x000D_
 _x000D_
 var i; //reuse var to iterate_x000D_
 _x000D_
 // Check objA values against objB_x000D_
 for (i in objA) {_x000D_
  //Protect against inherited properties_x000D_
  if(objA.hasOwnProperty(i)) {_x000D_
   if(objB.hasOwnProperty(i)) {_x000D_
    // Check if deep equal is valid_x000D_
    if(!simpleRecusiveDeepEqual( objA[i], objB[i] )) {_x000D_
     return false;_x000D_
    }_x000D_
   } else if(objA[i] != null) {_x000D_
    //ignore null values in objA, that objB does not have_x000D_
    //else fails_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
 }_x000D_
 _x000D_
 // Check if objB has additional values, that objA do not, fail if so_x000D_
 for (i in objB) {_x000D_
  if(objB.hasOwnProperty(i)) {_x000D_
   if(objB[i] != null && !objA.hasOwnProperty(i)) {_x000D_
    //ignore null values in objB, that objA does not have_x000D_
    //else fails_x000D_
    return false;_x000D_
   }_x000D_
  }_x000D_
 }_x000D_
 _x000D_
 // End of all checks_x000D_
 //--------------------------------------------_x000D_
 // By reaching here, all iteration scans have been done._x000D_
 // and should have returned false if it failed_x000D_
 return true;_x000D_
}_x000D_
_x000D_
// Sanity checking of simpleRecusiveDeepEqual_x000D_
(function() {_x000D_
 if(_x000D_
  // Basic checks_x000D_
  !simpleRecusiveDeepEqual({}, {}) ||_x000D_
  !simpleRecusiveDeepEqual([], []) ||_x000D_
  !simpleRecusiveDeepEqual(['a'], ['a']) ||_x000D_
  // Not strict checks_x000D_
  !simpleRecusiveDeepEqual("1", 1) ||_x000D_
  // Multiple objects check_x000D_
  !simpleRecusiveDeepEqual( { a:[1,2] }, { a:[1,2] }, { a:[1,2] } ) ||_x000D_
  // Ensure distinction between array and object (the following should fail)_x000D_
  simpleRecusiveDeepEqual( [1963], { 0:1963 } ) ||_x000D_
  // Null strict checks_x000D_
  simpleRecusiveDeepEqual( 0, null ) ||_x000D_
  simpleRecusiveDeepEqual( "", null ) ||_x000D_
  // Last "false" exists to make the various check above easy to comment in/out_x000D_
  false_x000D_
 ) {_x000D_
  alert("FATAL ERROR: simpleRecusiveDeepEqual failed basic checks");_x000D_
 } else { _x000D_
  //added this last line, for SO snippet alert on success_x000D_
  alert("simpleRecusiveDeepEqual: Passed all checks, Yays!");_x000D_
 }_x000D_
})();
_x000D_
_x000D_
_x000D_


If you are working in AngularJS, the angular.equals function will determine if two objects are equal. In Ember.js use isEqual.

  • angular.equals - See the docs or source for more on this method. It does a deep compare on arrays too.
  • Ember.js isEqual - See the docs or source for more on this method. It does not do a deep compare on arrays.

_x000D_
_x000D_
var purple = [{"purple": "drank"}];_x000D_
var drank = [{"purple": "drank"}];_x000D_
_x000D_
if(angular.equals(purple, drank)) {_x000D_
    document.write('got dat');_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
_x000D_
_x000D_
_x000D_


This question has more than 30 answers already. I am going to summarize and explain them (with a "my father" analogy) and add my suggested solution.

You have 4+1 classes of solutions:


1) Use a hacky incomplete quick one-liner

Good if you are in a rush and 99% correctness works.

Examples of this is, JSON.stringify() suggested by Pratik Bhalodiya, or JSON.encode by Joel Anair, or .toString(), or other methods that transform your objects into a String and then compare the two Strings using === character by character.

The drawback, however, is that there is no globally standard unique representation of an Object in String. e.g. { a: 5, b: 8} and {b: 8 and a: 5 } are equal.

  • Pros: Fast, quick.
  • Cons: Hopefully works! It will not work if the environment/browser/engine memorizes the ordering for objects (e.g. Chrome/V8) and the order of the keys are different (Thanks to Eksapsy.) So, not guaranteed at all. Performance wouldn't be great either in large objects.

My Father Analogy

When I am talking about my father, "my tall handsome father" and "my handsome tall father" are the same person! But the two strings are not the same.

Note that there is actually a correct (standard way) order of adjectives in English grammar, which says it should be a "handsome tall man," but you are risking your competency if you blindly assume Javascript engine of iOS 8 Safari is also abiding the same grammar, blindly! #WelcomeToJavascriptNonStandards


2) Write your own DIY recursive function

Good if you are learning.

Examples are atmin's solution.

The biggest disadvantage is you will definitely miss some edge cases. Have you considered a self-reference in object values? Have you considered NaN? Have you considered two objects that have the same ownProperties but different prototypical parents?

I would only encourage people to do this if they are practicing and the code is not going to go in production. That's the only case that reinventing the wheel has justifications.

  • Pros: Learning opportunity.
  • Cons: Not reliable. Takes time and concerns.

My Father Analogy

It's like assuming if my dad's name is "John Smith" and his birthday is "1/1/1970", then anyone whose name is "John Smith" and is born on "1/1/1970" is my father.

That's usually the case, but what if there are two "John Smith"s born on that day? If you think you will consider their height, then that's increasing the accuracy but still not a perfect comparison.

2.1 You limited scope DIY comparator

Rather than going on a wild chase of checking all the properties recursively, one might consider checking only "a limited" number of properties. For instance, if the objects are Users, you can compare their emailAddress field.

It's still not a perfect one, but the benefits over solution #2 are:

  1. It's predictable, and it's less likely to crash.
  2. You are driving the "definition" of equality, rather than relying on a wild form and shape of the Object and its prototype and nested properties.

3) Use a library version of equal function

Good if you need a production-level quality, and you cannot change the design of the system.

Examples are _.equal of lodash, already in coolaj86's answer or Angular's or Ember's as mentioned in Tony Harvey's answer or Node's by Rafael Xavier.

  • Pros: It's what everyone else does.
  • Cons: External dependency, which can cost you extra memory/CPU/Security concerns, even a little bit. Also, can still miss some edge cases (e.g. whether two objects having same ownProperties but different prototypical parents should be considered the same or not.) Finally, you might be unintentionally band-aiding an underlying design problem with this; just saying!

My Father Analogy

It's like paying an agency to find my biological father, based on his phone, name, address, etc.

It's gonna cost more, and it's probably more accurate than myself running the background check, but doesn't cover edge cases like when my father is immigrant/asylum and his birthday is unknown!


4) Use an IDentifier in the Object

Good if you [still] can change the design of the system (objects you are dealing with) and you want your code to last long.

It's not applicable in all cases, and might not be very performant. However, it's a very reliable solution, if you can make it.

The solution is, every object in the system will have a unique identifier along with all the other properties. The uniqueness of the identifier will be guaranteed at the time of generation. And you will use this ID (also known as UUID/GUID -- Globally/Universally Unique Identifier) when it comes to comparing two objects. i.e. They are equal if and only if these IDs are equal.

The IDs can be simple auto_incremental numbers, or a string generated via a library (advised) or a piece of code. All you need to do is make sure it's always unique, which in case of auto_incremental it can be built-in, or in case of UUID, can be checked will all existing values (e.g. MySQL's UNIQUE column attribute) or simply (if coming from a library) be relied upon giving the extremely low likelihood of a collision.

Note that you also need to store the ID with the object at all times (to guarantee its uniqueness), and computing it in real-time might not be the best approach.

  • Pros: Reliable, efficient, not dirty, modern.
  • Cons: Needs extra space. Might need a redesign of the system.

My Father Analogy

It's like known my father's Social Security Number is 911-345-9283, so anyone who has this SSN is my father, and anyone who claims to be my father must have this SSN.


Conclusion

I personally prefer solution #4 (ID) over them all for accuracy and reliability. If it's not possible I'd go with #2.1 for predictability, and then #3. If neither is possible, #2 and finally #1.


One additional option, is use equals of Ramda library:

const c = {a: 1, b: 2};
const d = {b: 2, a: 1};
R.equals(c, d); //=> true

I just wrote this method just to be sure that arrays and objects are both compared in a clear way.

This should do the trick as well! :)

public class Objects {
    /**
     * Checks whether a value is of type Object
     * @param value the value
     */
    public static isObject = (value: any): boolean => {
        return value === Object(value) && Object.prototype.toString.call(value) !== '[object Array]'
    }

    /**
     * Checks whether a value is of type Array
     * @param value the value
     */
    public static isArray = (value: any): boolean => {
        return Object.prototype.toString.call(value) === '[object Array]' && !Objects.isObject(value)
    }

    /**
     * Check whether two values are equal
     */
    public static isEqual = (objectA: any, objectB: any) => {
        // Objects
        if (Objects.isObject(objectA) && !Objects.isObject(objectB)) {
            return false
        }
        else if (!Objects.isObject(objectA) && Objects.isObject(objectB)) {
            return false
        }
        // Arrays
        else if (Objects.isArray(objectA) && !Objects.isArray(objectB)) {
            return false
        }
        else if (!Objects.isArray(objectA) && Objects.isArray(objectB)) {
            return false
        }
        // Primitives
        else if (!Objects.isArray(objectA) && !Objects.isObject(objectA)) {
            return objectA === objectB
        }
        // Object or array
        else {
            const compareObject = (objectA: any, objectB: any): boolean => {
                if (Object.keys(objectA).length !== Object.keys(objectB).length) return false

                for (const propertyName of Object.keys(objectA)) {
                    const valueA = objectA[propertyName]
                    const valueB = objectB[propertyName]

                    if (!Objects.isEqual(valueA, valueB)) {
                        return false
                    }
                }

                return true
            }
            const compareArray = (arrayA: any[], arrayB: any[]): boolean => {
                if (arrayA.length !== arrayB.length) return false

                for (const index in arrayA) {
                    const valueA = arrayA[index]
                    const valueB = arrayB[index]

                    if (!Objects.isEqual(valueA, valueB)) {
                        return false
                    }
                }

                return true
            }
            if (Objects.isObject(objectA)) {
                return compareObject(objectA, objectB)
            } else {
                return compareArray(objectA, objectB)
            }
        }
    }
}

Why reinvent the wheel? Give Lodash a try. It has a number of must-have functions such as isEqual().

_.isEqual(object, other);

It will brute force check each key value - just like the other examples on this page - using ECMAScript 5 and native optimizations if they're available in the browser.

Note: Previously this answer recommended Underscore.js, but lodash has done a better job of getting bugs fixed and addressing issues with consistency.


Just wanted to contribute my version of objects comparison utilizing some es6 features. It doesn't take an order into account. After converting all if/else's to ternary I've came with following:

function areEqual(obj1, obj2) {

    return Object.keys(obj1).every(key => {

            return obj2.hasOwnProperty(key) ?
                typeof obj1[key] === 'object' ?
                    areEqual(obj1[key], obj2[key]) :
                obj1[key] === obj2[key] :
                false;

        }
    )
}

For comparing keys for simple key/value pairs object instances, I use:

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

Once keys are compared, a simple additional for..in loop is enough.

Complexity is O(N*N) with N is the number of keys.

I hope/guess objects I define won't hold more than 1000 properties...


  1. sort the objects (dictionary)
  2. compare JSON string

    function areTwoDictsEqual(dictA, dictB) {
        function sortDict(dict) {
            var keys = Object.keys(dict);
            keys.sort();
    
            var newDict = {};
            for (var i=0; i<keys.length; i++) {
                var key = keys[i];
                var value = dict[key];
                newDict[key] = value;
            } 
            return newDict;
        }
    
        return JSON.stringify(sortDict(dictA)) == JSON.stringify(sortDict(dictB));
    }
    

A simple solution to this issue that many people don't realize is to sort the JSON strings (per character). This is also usually faster than the other solutions mentioned here:

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

Another useful thing about this method is you can filter comparisons by passing a "replacer" function to the JSON.stringify functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter). The following will only compare all objects keys that are named "derp":

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.


If you are comparing JSON objects you can use https://github.com/mirek/node-rus-diff

npm install rus-diff

Usage:

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

If two objects are different, a MongoDB compatible {$rename:{...}, $unset:{...}, $set:{...}} like object is returned.


If you are using a JSON library, you can encode each object as JSON, then compare the resulting strings for equality.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

NOTE: While this answer will work in many cases, as several people have pointed out in the comments it's problematic for a variety of reasons. In pretty much all cases you'll want to find a more robust solution.


Lot's of good thoughts here! Here is my version of deep equal. I posted it on github and wrote some tests around it. It's hard to cover all the possible cases and sometimes it's unnecessary to do so.

I covered NaN !== NaN as well as circular dependencies.

https://github.com/ryancat/simple-deep-equal/blob/master/index.js


Some of the following solutions have problems with performance, functionality and style... They are not thought through enough, and some of them fail for different cases. I tried to address this problem in my own solution, and I would really much appreciate your feedback:

http://stamat.wordpress.com/javascript-object-comparison/

//Returns the object's class, Array, Date, RegExp, Object are of interest to us
var getClass = function(val) {
    return Object.prototype.toString.call(val)
        .match(/^\[object\s(.*)\]$/)[1];
};

//Defines the type of the value, extended typeof
var whatis = function(val) {

    if (val === undefined)
        return 'undefined';
    if (val === null)
        return 'null';

    var type = typeof val;

    if (type === 'object')
        type = getClass(val).toLowerCase();

    if (type === 'number') {
        if (val.toString().indexOf('.') > 0)
            return 'float';
        else
        return 'integer';
    }

    return type;
   };

var compareObjects = function(a, b) {
    if (a === b)
        return true;
    for (var i in a) {
        if (b.hasOwnProperty(i)) {
            if (!equal(a[i],b[i])) return false;
        } else {
            return false;
        }
    }

    for (var i in b) {
        if (!a.hasOwnProperty(i)) {
            return false;
        }
    }
    return true;
};

var compareArrays = function(a, b) {
    if (a === b)
        return true;
    if (a.length !== b.length)
        return false;
    for (var i = 0; i < a.length; i++){
        if(!equal(a[i], b[i])) return false;
    };
    return true;
};

var _equal = {};
_equal.array = compareArrays;
_equal.object = compareObjects;
_equal.date = function(a, b) {
    return a.getTime() === b.getTime();
};
_equal.regexp = function(a, b) {
    return a.toString() === b.toString();
};
//  uncoment to support function as string compare
//  _equal.fucntion =  _equal.regexp;



/*
 * Are two values equal, deep compare for objects and arrays.
 * @param a {any}
 * @param b {any}
 * @return {boolean} Are equal?
 */
var equal = function(a, b) {
    if (a !== b) {
        var atype = whatis(a), btype = whatis(b);

        if (atype === btype)
            return _equal.hasOwnProperty(atype) ? _equal[atype](a, b) : a==b;

        return false;
    }

    return true;
};

Are you trying to test if two objects are the equal? ie: their properties are equal?

If this is the case, you'll probably have noticed this situation:

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

you might have to do something like this:

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

Obviously that function could do with quite a bit of optimisation, and the ability to do deep checking (to handle nested objects: var a = { foo : { fu : "bar" } }) but you get the idea.

As FOR pointed out, you might have to adapt this for your own purposes, eg: different classes may have different definitions of "equal". If you're just working with plain objects, the above may suffice, otherwise a custom MyClass.equals() function may be the way to go.


_x000D_
_x000D_
const obj = {
  name: "Carl",
  age: 15
}
const obj2 = {
  name: "Carl",
  age: 15,
}


const compareObj = (objects) => {
  const res =  objects.map((item) => {
    return Object.entries(item).flat().join()
  })
  return res.every((a) => {
    return a === res[0]
  })
}

console.log(compareObj([obj,obj2]))
_x000D_
_x000D_
_x000D_


Short functional deepEqual implementation:

function deepEqual(x, y) {
  return (x && y && typeof x === 'object' && typeof y === 'object') ?
    (Object.keys(x).length === Object.keys(y).length) &&
      Object.keys(x).reduce(function(isEqual, key) {
        return isEqual && deepEqual(x[key], y[key]);
      }, true) : (x === y);
}

Edit: version 2, using jib's suggestion and ES6 arrow functions:

function deepEqual(x, y) {
  const ok = Object.keys, tx = typeof x, ty = typeof y;
  return x && y && tx === 'object' && tx === ty ? (
    ok(x).length === ok(y).length &&
      ok(x).every(key => deepEqual(x[key], y[key]))
  ) : (x === y);
}

In Node.js, you can use its native require("assert").deepStrictEqual. More info: http://nodejs.org/api/assert.html

For example:

var assert = require("assert");
assert.deepStrictEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError

Another example that returns true / false instead of returning errors:

var assert = require("assert");

function deepEqual(a, b) {
    try {
      assert.deepEqual(a, b);
    } catch (error) {
      if (error.name === "AssertionError") {
        return false;
      }
      throw error;
    }
    return true;
};

This is a simple Javascript function to compare two objects having simple key-value pairs. The function will return an array of strings, where each string is a path to an inequality between the two objects.

function compare(a,b) {
    var paths = [];
    [...new Set(Object.keys(a).concat(Object.keys(b)))].forEach(key=>{
        if(typeof a[key] === 'object' && typeof b[key] === 'object') {
            var results = compare(a[key], b[key]);
            if(JSON.stringify(results)!=='[]') {
                paths.push(...results.map(result=>key.concat("=>"+result)));
            }
        }
        else if (a[key]!==b[key]) {
            paths.push(key);
        }
    })
    return paths;
}

If you only want to compare two objects without knowing the paths to inequalities, you can do it as follows:

if(JSON.stringify(compare(object1, object2))==='[]') {
   // the two objects are equal
} else {
   // the two objects are not equal
}

How to determine that the partial object (Partial<T>) is equal to the original object (T) in typescript.

function compareTwoObjects<T>(original: T, partial: Partial<T>): boolean {
  return !Object.keys(partial).some((key) => partial[key] !== original[key]);
}

P.S. Initially I was planning to create a new question with an answer. But such a question already exists and marked as a duplicate.


Heres's a solution in ES6/ES2015 using a functional-style approach:

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

demo available here


Depends on what you mean by equality. And therefore it is up to you, as the developer of the classes, to define their equality.

There's one case used sometimes, where two instances are considered 'equal' if they point to the same location in memory, but that is not always what you want. For instance, if I have a Person class, I might want to consider two Person objects 'equal' if they have the same Last Name, First Name, and Social Security Number (even if they point to different locations in memory).

On the other hand, we can't simply say that two objects are equal if the value of each of their members is the same, since, sometimes, you don't want that. In other words, for each class, it's up to the class developer to define what members make up the objects 'identity' and develop a proper equality operator (be it via overloading the == operator or an Equals method).

Saying that two objects are equal if they have the same hash is one way out. However you then have to wonder how the hash is calculated for each instance. Going back to the Person example above, we could use this system if the hash was calculated by looking at the values of the First Name, Last Name, and Social Security Number fields. On top of that, we are then relying on the quality of the hashing method (that's a huge topic on its own, but suffice it to say that not all hashes are created equal, and bad hashing methods can lead to more collisions, which in this case would return false matches).


Though there are so many answers to this question already. My attempt is just to provide one more way of implementing this:

_x000D_
_x000D_
const primitveDataTypes = ['number', 'boolean', 'string', 'undefined'];_x000D_
const isDateOrRegExp = (value) => value instanceof Date || value instanceof RegExp;_x000D_
const compare = (first, second) => {_x000D_
    let agg = true;_x000D_
    if(typeof first === typeof second && primitveDataTypes.indexOf(typeof first) !== -1 && first !== second){_x000D_
        agg =  false;_x000D_
    }_x000D_
    // adding support for Date and RegExp._x000D_
    else if(isDateOrRegExp(first) || isDateOrRegExp(second)){_x000D_
        if(first.toString() !== second.toString()){_x000D_
            agg = false;_x000D_
        }_x000D_
    }_x000D_
    else {_x000D_
        if(Array.isArray(first) && Array.isArray(second)){_x000D_
        if(first.length === second.length){_x000D_
             for(let i = 0; i < first.length; i++){_x000D_
                if(typeof first[i] === 'object' && typeof second[i] === 'object'){_x000D_
                    agg = compare(first[i], second[i]);_x000D_
                }_x000D_
                else if(first[i] !== second[i]){_x000D_
                    agg = false;_x000D_
                }_x000D_
            }_x000D_
        } else {_x000D_
            agg = false;_x000D_
        }_x000D_
    } else {_x000D_
        const firstKeys = Object.keys(first);_x000D_
        const secondKeys = Object.keys(second);_x000D_
        if(firstKeys.length !== secondKeys.length){_x000D_
            agg = false;_x000D_
        }_x000D_
        for(let j = 0 ; j < firstKeys.length; j++){_x000D_
            if(firstKeys[j] !== secondKeys[j]){_x000D_
                agg = false;_x000D_
            }_x000D_
            if(first[firstKeys[j]] && second[secondKeys[j]] && typeof first[firstKeys[j]] === 'object' && typeof second[secondKeys[j]] === 'object'){_x000D_
                agg = compare(first[firstKeys[j]], second[secondKeys[j]]);_x000D_
             } _x000D_
             else if(first[firstKeys[j]] !== second[secondKeys[j]]){_x000D_
                agg = false;_x000D_
             } _x000D_
        }_x000D_
    }_x000D_
    }_x000D_
    return agg;_x000D_
}_x000D_
_x000D_
_x000D_
console.log('result', compare({a: 1, b: { c: [4, {d:5}, {e:6}]}, r: null}, {a: 1, b: { c: [4, {d:5}, {e:6}]}, r: 'ffd'}));  //returns false.
_x000D_
_x000D_
_x000D_


I see spaghetti code answers. Without using any third party libs, this is very easy.

Firstly sort the two objects by key their key names.

let objectOne = { hey, you }
let objectTwo = { you, hey }

// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
    return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}

let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)

Then simply use a string to compare them.

JSON.stringify(objectOne) === JSON.stringify(objectTwo)

Simplest and logical solutions for comparing everything Like Object, Array, String, Int...

JSON.stringify({a: val1}) === JSON.stringify({a: val2})

Note:

  • you need to replace val1and val2 with your Object
  • for the object, you have to sort(by key) recursively for both side objects

I'm making the following assumptions with this function:

  1. You control the objects you are comparing and you only have primitive values (ie. not nested objects, functions, etc.).
  2. Your browser has support for Object.keys.

This should be treated as a demonstration of a simple strategy.

/**
 * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
 * @param {Object} object1
 * @param {Object} object2
 * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
 * @returns {Boolean}
 */
function isEqual( object1, object2, order_matters ) {
    var keys1 = Object.keys(object1),
        keys2 = Object.keys(object2),
        i, key;

    // Test 1: Same number of elements
    if( keys1.length != keys2.length ) {
        return false;
    }

    // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
    // keys1 = Object.keys({a:2, b:1}) = ["a","b"];
    // keys2 = Object.keys({b:1, a:2}) = ["b","a"];
    // This is why we are sorting keys1 and keys2.
    if( !order_matters ) {
        keys1.sort();
        keys2.sort();
    }

    // Test 2: Same keys
    for( i = 0; i < keys1.length; i++ ) {
        if( keys1[i] != keys2[i] ) {
            return false;
        }
    }

    // Test 3: Values
    for( i = 0; i < keys1.length; i++ ) {
        key = keys1[i];
        if( object1[key] != object2[key] ) {
            return false;
        }
    }

    return true;
}

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to object

How to update an "array of objects" with Firestore? how to remove json object key and value.? Cast object to interface in TypeScript Angular 4 default radio button checked by default How to use Object.values with typescript? How to map an array of objects in React How to group an array of objects by key push object into array Add property to an array of objects access key and value of object using *ngFor

Examples related to equals

this in equals method Why do we have to override the equals() method in Java? Compare two objects with .equals() and == operator Check if bash variable equals 0 Setting equal heights for div's with jQuery Java, how to compare Strings with String Arrays How can I express that two values are not equal to eachother? How to override equals method in Java How do you say not equal to in Ruby? Getting an element from a Set

Examples related to hashcode

Hashing with SHA1 Algorithm in C# HashMaps and Null values? How to create a HashMap with two keys (Key-Pair, Value)? What is hashCode used for? Is it unique? How does a Java HashMap handle different objects with the same hash code? Hashcode and Equals for Hashset What is the use of hashCode in Java? Good Hash Function for Strings Why do I need to override the equals and hashCode methods in Java? Memory address of variables in Java