JS: Test Equality of Objects

By Xah Lee. Date: . Last updated: .

This page shows you a function to compare equality of objects by deep dive.

JavaScript doesn't have a buildin way to compare equality of 2 objects.

const c = {"a":3};
const d = {"a":3};

console.log( c === d ); // false

When a object is assigned to a variable, the variable holds a reference to the object.

If 2 variables hold the same reference, they are equal.

but 2 objects with same property and parent etc, will have different reference.

const x = {"a":3};
const y = x; // x and y holds the same reference

console.log( x === y ); // true

const z = {"a":3};

console.log( z === y ); // false

console.log( z === x ); // false

console.log(z); // {a:3}
console.log(y); // {a:3}

Function to Compare Object Equality

Here's functions to compare object equality. The object's enumerable properties are compared, one by one. If a property's value is object (or array), recursion is applied. Returns true if all enumerable property values are equal.

const xah_is_obj_equal = ((obj1, obj2) =>
{

/* [
    return true if 2 obj are equal.
    equal here means deep compare enumerable properties of object

    http://xahlee.info/js/js_comparison_equality_test_objects.html
    version 2017-09-24
 ] */

    const keys1 = Object.keys(obj1).sort();
    const keys2 = Object.keys(obj2).sort();

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

    // first make sure have same keys. may save time
    if ( ! keys1.every( ((k, i) => (k === keys2[i])) ) ) {
        return false;
    }

    // check if any value is not equal
    return keys1.every ( ((kk) => {
        const v1 = obj1[kk];
        const v2 = obj2[kk];
        if ( Array.isArray(v1) )  {
            return xah_is_array_equal(v1,v2);
        } else if ( typeof v1 === "object" && v1 !== null) {
            return xah_is_obj_equal(v1,v2);
        } else {
            return  v1 === v2;
        }
    })  );
});

const xah_is_array_equal = ((array1, array2) =>
{

/* [
    return true if 2 array are equal
    allow array-like object
    allow nested array

    http://xahlee.info/js/js_comparison_equality_test_objects.html
    version 2017-09-24
 ] */

    // allow array-like object
    if ( Array.isArray(array1) !== Array.isArray(array2) ) { return false; }
    if (array1.length !== array2.length) { return false; }

    return Array.prototype.every.call(
        array1,
        ((x, i) => {
            const y = array2[i];
            if ( Array.isArray(x) ) {
                if ( ! Array.isArray(y) ) {
                    return false;}
                else {
                    return xah_is_array_equal(x, y); }
            } else if ( typeof x === "object" && typeof x !== null) {
                if (! ( typeof y === "object" && typeof y !== null)) {
                    return false;}
                else {
                    return xah_is_obj_equal(x,y); }
            } else {
                return (x === y);
            }
        })
    );
});

// ------------------------------------------------------
// tests

console.log(
    // simple obj
    xah_is_obj_equal({"a":1}, {"a":1}),

    // diff value
    ! xah_is_obj_equal({"a":1}, {"a":2}),

    // num of obj not same
    ! xah_is_obj_equal({"a":1,"b":2}, {"a":1}),

    // diff order
    xah_is_obj_equal({"a":1,"b":2}, {"b":2,"a":1}),

    // test empty obj
    xah_is_obj_equal({}, {}),

    // nested obj
    xah_is_obj_equal(
        {"a":1,"b":{"c":3}},
        {"a":1,"b":{"c":3}})
);

// nested obj with diff value
console.log(
    ! xah_is_obj_equal(
        {"a":1,"b":{"c":1}},
        {"a":1,"b":{"c":2}})
,
// deeper nesting
    xah_is_obj_equal(
        {"a":1,"b":{"c":3, "mm":{"x1":1,"x2":{"x3":3}}}},
        {"a":1,"b":{"c":3, "mm":{"x1":1,"x2":{"x3":3}}}})
,
// works on array-like obj
    xah_is_obj_equal(
        {0:3,1:4,"length":2},
        {0:3,1:4,"length":2})
,
// works on array obj
    xah_is_obj_equal(
        [3, {0:3,1:4,"length":2}, [[2,7],9]],
        [3, {0:3,1:4,"length":2}, [[2,7],9]])
);

// ----------------------------------------------

// test on array objects
console.log (
    xah_is_array_equal([3,4], [3,4])
    ,
    ! xah_is_array_equal([3,4], [4,3])
    ,
    ! xah_is_array_equal([3,4], [3])
    ,
    xah_is_array_equal([], [])
    ,
    // array-like objects
    xah_is_array_equal(
        {0:3,1:4,"length":2},
        {0:3,1:4,"length":2}
    )
    ,
    // nested array
    xah_is_array_equal(
        [3,4, [[2,7],9]],
        [3,4, [[2,7],9]])
    ,
    // negation
    ! xah_is_array_equal(
        [3,4, {"t":2}],
        [3,4, {"t":2, "b":2}])
    ,
    xah_is_array_equal(
        [ {"b":1},4],
        [ {"b":1},4])
);

Pre ES2015 Version

function xah_is_obj_equal (obj1, obj2) {
    // return true if 2 obj are equal.
    // equal here means deep compare enumerable properties of object

    // http://xahlee.info/js/js_comparison_equality_test_objects.html
    // version 2016-04-20

    const keys1 = Object.keys(obj1).sort();
    const keys2 = Object.keys(obj2).sort();

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

    // first make sure have same keys. may save time
    if ( ! keys1.every( function(k, i) { return (k === keys2[i]); } ) ) {
        return false;
    }

    // check if any value is not equal
    return keys1.every (function(kk) {
        const v1 = obj1[kk];
        const v2 = obj2[kk];
        if ( Array.isArray(v1) )  {
            return xah_is_array_equal(v1,v2);
        } else if ( typeof v1 === "object" && v1 !== null) {
            return xah_is_obj_equal(v1,v2);
        } else {
            return  v1 === v2;
        }
    } );
}

function xah_is_array_equal (array1, array2) {
    // return true if 2 array are equal
    // allow array-like object
    // allow nested array

    // http://xahlee.info/js/js_comparison_equality_test_objects.html
    // version 2016-04-20

    // allow array-like object
    if ( Array.isArray(array1) !== Array.isArray(array2) ) { return false; }
    if (array1.length !== array2.length) { return false; }

    return Array.prototype.every.call(
        array1,
        function(x, i) {
            const y = array2[i];
            if ( Array.isArray(x) ) {
                if ( ! Array.isArray(y) ) {
                    return false;}
                else {
                    return xah_is_array_equal(x, y); }
            } else if ( typeof x === "object" && typeof x !== null) {
                if (! ( typeof y === "object" && typeof y !== null)) {
                    return false;}
                else {
                    return xah_is_obj_equal(x,y); }
            } else {
                return (x === y);
            }
        }
    );
}

// ------------------------------------------------------
// tests

console.log(
    // simple obj
    xah_is_obj_equal({"a":1}, {"a":1}),

    // diff value
    ! xah_is_obj_equal({"a":1}, {"a":2}),

    // num of obj not same
    ! xah_is_obj_equal({"a":1,"b":2}, {"a":1}),

    // diff order
    xah_is_obj_equal({"a":1,"b":2}, {"b":2,"a":1}),

    // test empty obj
    xah_is_obj_equal({}, {}),

    // nested obj
    xah_is_obj_equal(
        {"a":1,"b":{"c":3}},
        {"a":1,"b":{"c":3}})
);

// nested obj with diff value
console.log(
    ! xah_is_obj_equal(
        {"a":1,"b":{"c":1}},
        {"a":1,"b":{"c":2}})
,
// deeper nesting
    xah_is_obj_equal(
        {"a":1,"b":{"c":3, "mm":{"x1":1,"x2":{"x3":3}}}},
        {"a":1,"b":{"c":3, "mm":{"x1":1,"x2":{"x3":3}}}})
,
// works on array-like obj
    xah_is_obj_equal(
        {0:3,1:4,"length":2},
        {0:3,1:4,"length":2})
,
// works on array obj
    xah_is_obj_equal(
        [3, {0:3,1:4,"length":2}, [[2,7],9]],
        [3, {0:3,1:4,"length":2}, [[2,7],9]])
);

// ----------------------------------------------

// test on array objects
console.log (
    xah_is_array_equal([3,4], [3,4])
    ,
    ! xah_is_array_equal([3,4], [4,3])
    ,
    ! xah_is_array_equal([3,4], [3])
    ,
    xah_is_array_equal([], [])
    ,
    // array-like objects
    xah_is_array_equal(
        {0:3,1:4,"length":2},
        {0:3,1:4,"length":2}
    )
    ,
    // nested array
    xah_is_array_equal(
        [3,4, [[2,7],9]],
        [3,4, [[2,7],9]])
    ,
    // negation
    ! xah_is_array_equal(
        [3,4, {"t":2}],
        [3,4, {"t":2, "b":2}])
    ,
    xah_is_array_equal(
        [ {"b":1},4],
        [ {"b":1},4])
);

Comparison by JSON, Ordering Problem

If you turn object into JSON string, then compare the string, this is not reliable because object properties is not ordered.

// comparison by JSON.stringify is not reliable

const x = {"a":1, "b":2};
const y = {"b":2, "a":1}; // reverse order

console.log( JSON.stringify(x) === JSON.stringify(y) ); // false

see also JS: Compare Array Equality

JS Array

  1. Understand JS Array
  2. Create Array
  3. Sparse Array
  4. Array-Like Object
  5. Array How-To
  6. Array Object
  7. Array.prototype

JS Object and Inheritance

  1. Object Overview
  2. Object Type
  3. Prototype and Inheritance
  4. Create Object
  5. Object Literal Expression
  6. Create Object with Parent X
  7. Get/Set Prototype
  8. Prevent Adding Property
  9. Determine Type of Object
  10. Clone Object
  11. Test Object Equality
  12. Add Method to Prototype
  13. Object Object
  14. Object.prototype
Liket it? Put $5 at patreon.

Or, Buy JavaScript in Depth

If you have a question, put $5 at patreon and message me.

Web Dev Tutorials

  1. HTML
  2. Visual CSS
  3. JS in Depth
  4. JS Reference
  5. DOM
  6. SVG
  7. Web Dev Blog