walexy
walexy

Reputation: 667

Deep equal object comparison in JavaScript

Am reading Eloquent javascript and I was given a task to write a deep equal function for objects.

My code works well for object without nested object but when i pass two object that has a nested object in it my code fails.

i tried debugging it and i noticed that anytime the function encounters a nested object, it doesn't transfer control back to the main object.

Take for example i have two object a and b below:

let a = {
  name: "ade",
  last: "segun",
  dead: {
    name: "ade",
    last: "segun",
  },
  eaten: true,
};

let b = {
  name: "ade",
  last: "segun",
  dead: {
    name: "ade",
    last: "segun",
  },
  eaten: false,
};

After the function checks for the dead property which is a nested object, it doesn't return to the main object and checks for eaten property.

What did I do wrong? This is My code

let a = { name: "ade", last: "segun", dead: { name: "ade", last: "segun", }, eaten: true, }; 
let b = { name: "ade", last: "segun", dead: { name: "ade", last: "segun", }, eaten: false, };


const deepEqual = (obj1, obj2) => {
  const keysA = Object.keys(obj1);
  const keysB = Object.keys(obj2);
  if (keysA.length !== keysB.length) {
    return false;
  }
  let c;
  for (let key of keysA) {
    // c checks whether the key is part of keysB array
    c = keysB[keysB.indexOf(key)];
    if (key !== c) {
      return false;
    }
    if (
      typeof obj1[key] === "object" &&
      typeof obj2[c] === "object" &&
      obj1[key] !== null &&
      obj2[c] !== null
    ) {
      return deepEqual(obj1[key], obj2[c]);
    } else {
      if (obj1[key] !== obj2[c]) return false;
    }
  }
  return true;
};

console.log(deepEqual(a, b)); //true

Upvotes: 0

Views: 2814

Answers (2)

Spiritcoder
Spiritcoder

Reputation: 39

Thanks for your code. You saved me so much time. Exactly what I needed. But my implementation was to find the deep difference between two objects.

I just had to edit the code a little. I will drop it for someone that might have the same issue I was trying to solve

    const differenceObj = {
    };

    const deepEqual = (obj1: any, obj2: any) => {
        const keysA = Object.keys(obj1);
        const keysB = Object.keys(obj2);
        if (keysA.length !== keysB.length) {
            return false;
        }
        let c;
        for (const key of keysA) {
            c = keysB[keysB.indexOf(key)];
            if (key !== c) {
                return false;
            }
            if (
                typeof obj1[key] === 'object' &&
                typeof obj2[c] === 'object' &&
                obj1[key] !== null &&
                obj2[c] !== null
            ) {
                deepEqual(obj1[key], obj2[c]);
            }
            if (obj1[key] !== obj2[c]) {
                differenceObj[key] = {
                    new: obj1[key],
                    old: obj2[key],
                };
            }
        }

        return differenceObj;
    
}

I had to return the old and the new values which represents the differences.

Upvotes: 0

raina77ow
raina77ow

Reputation: 106385

This line in your code...

return deepEqual(obj1[key], obj2[c]);

... basically makes the comparison function to stop when the first nested object is encountered. What should happen instead is 1) result of deepEqual is calculated, and 2) only if it's false, the function returns it immediately. For example:

const isDeeplyEqual = deepEqual(obj1[key], obj2[c]);
if (!isDeeplyEqual) return false;

... or just:

if (!deepEqual(obj1[key], obj2[c])) return false;

Upvotes: 3

Related Questions