1

I'm attempting deep object comparison using recursion, but my function is returning undefined.

I know there are better ways to compare objects (IE JSON.Stringify()) but I'm not understanding why my function is returning undefined.

function deepObjCompare(obj1, obj2) {

  Object.keys(obj1).forEach((key) => {
    const key1 = obj1[key];
    const key2 = obj2[key];

    if (key2) {
      if (typeof key1 === "object" && key1 !== null) {
        deepObjCompare(key1, key2);
      } else if (key1 === key2) {
        return true;
      }
    }
    return false;
  });
}

const obj1 = {
  name: "Bill",
  address: {
    cityNow: "Paris",
    cityFuture: "NYC"
  },
  age: 39
};

const obj2 = {
  name: "Bill",
  address: {
    cityNow: "Paris",
    cityFuture: "NYC"
  },
  age: 39
};

const obj3 = {
  name: "Bob",
  address: "Paris",
  age: 39
};

console.log(deepObjCompare(obj1, obj3));
CRice
  • 29,968
  • 4
  • 57
  • 70
Chunky Chunk
  • 16,553
  • 15
  • 84
  • 162

3 Answers3

2

You can't return from a forEach loop, and you have to return the recursive call:

function deepObjCompare(obj1, obj2) {

  let keys = Object.keys(obj1);
  return keys.every((key) => { // use a for-of loop instead of forEach
    const key1 = obj1[key];
    const key2 = obj2[key];

    if (key2) {
      if (typeof key1 === "object" && key1 !== null) {
         return deepObjCompare(key1, key2); // return the recursive call
      } else if (key1 === key2) {
        return true;
      }
    }
    return false;
  });
}

const obj1 = {name: "Bill",address: {cityNow: "Paris",cityFuture: "NYC"},age: 39};
const obj2 = {name: "Bill",address: {cityNow: "Paris",cityFuture: "NYC"},age: 39};
const obj3 = {name: "Bill",address: "Paris",age: 39};

console.log("Are Obj1 and Obj3 equal? ",deepObjCompare(obj1, obj3));
console.log("Are Obj1 and Obj2 equal? ",deepObjCompare(obj1, obj2));
Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
2

I see three main issues here:

  • deepObjCompare lacks a return statement, which is why it is implicitly returning undefined.
  • The .forEach method always returns undefined, so you'll want to change that to another method that will return an actual value. I think .every is what you're after here.
  • You do not return the result of your recursive call.

All together, that would change your snippet to the following:

function deepObjCompare(obj1, obj2) {

  return Object.keys(obj1).every((key) => { // Use .every and return the result!
    const key1 = obj1[key];
    const key2 = obj2[key];

    if (key2) {
      if (typeof key1 === "object" && key1 !== null) {
        return deepObjCompare(key1, key2); // Return the result of your recursive call!
      } else if (key1 === key2) {
        return true;
      }
    }
    return false;
  });
}

const obj1 = {
  name: "Bill",
  address: {
    cityNow: "Paris",
    cityFuture: "NYC"
  },
  age: 39
};

const obj2 = {
  name: "Bill",
  address: {
    cityNow: "Paris",
    cityFuture: "NYC"
  },
  age: 39
};

const obj3 = {
  name: "Bob",
  address: "Paris",
  age: 39
};

console.log(deepObjCompare(obj1, obj3)); // false
console.log(deepObjCompare(obj1, obj2)); // true
CRice
  • 29,968
  • 4
  • 57
  • 70
-1

There are actually a number of things I see that are wrong with this implementation. But as to why it's returning undefined - that's because your function never actually returns anything. All your return statements are inside the function passed to forEach, and therefore do nothing with regard to the outer deepObjCompare.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • 1
    Can someone please explain the down votes? I appreciate I didn't give a solution to comparing objects, and therefore it's not as good as other answers given. But my time was limited and it sounded like the OP just wanted to know why they were getting `undefined`, with a view to fixing it themselves. And I believe my answer is correct on that point. No hard feelings, I'm just relatively new to participating on SO and would like to learn from my mistakes. – Robin Zigmond Sep 26 '18 at 18:07
  • 1
    I can't explain the downvotes, other than perhaps readers thought your contribution was rather short. It is nice when people explain their vote, but they are not required to; they are anonymous by design. My view is that while anyone is welcome to add a comment asking for an explanation, it is probably a waste of time, since the downvoter has usually long gone. – halfer Sep 27 '18 at 21:03