1

Can someone walk me through the recursion function in this code?, !deepEqual(a[key], b[key]). How it compares its values every time it is called?...

function deepEqual(a, b) {
  if (a === b) return true;
  
  if (a == null || typeof a != "object" ||
      b == null || typeof b != "object") return false;

  let keysA = Object.keys(a), keysB = Object.keys(b);

  if (keysA.length != keysB.length) return false;

  for (let i = 0; i <= keysA.length -1; i++) {
     let key = keysA[i];
    if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
  }

  return true;
}

let obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: {is: "as"}, object: 3}));
// → false
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
// → true

I really need to understand how the recursion function loop get through the second call without returning true on the first check and false on the second check for if (a == null || typeof a != "object" || b == null || typeof b != "object") return false;

Because the value of !deepEqual(a["is"], b["is"])) == !deepEqual("is", "is")) and thus should return true; on the first check for if (a === b) return true;. and return false; on the second check for if (a == null || typeof a != "object" || b == null || typeof b != "object") return false; because its not an object.

wont that stop the function from completing the check for the remaining properties?

can anyone make this clear enough for me?

let obj = {here: {is: "an", that: "at", name: "ola", here: {is: "as"}, object: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: {is: "an", that: "at", name: "ola", here: {is: "as"}, object: 3}));
// → false


//The only different property value is in the second argument's last property. 
OJay
  • 63
  • 1
  • 6
  • if you want to compare two object then just convert them both into string and then check equality. – Arif Rathod Sep 24 '18 at 05:35
  • @ArifRathod that only works if javascript guarantees ordering of keys alphabetically when stringified. I don't believe there is such a guarantee – pinkfloydx33 Sep 24 '18 at 05:54
  • yes, you are right, so you should sort object first then you can compare. that will works. i don't think that we should write very long and complex logic to compare both object. – Arif Rathod Sep 24 '18 at 06:01
  • So can someone illustrate this for me in a break down code form or diagram that i can look at . I'll catch the idea if it is visible – OJay Sep 24 '18 at 19:58
  • @Ola-Juwon I think you will enjoy [this Q&A](https://stackoverflow.com/a/33233053/633183) – Mulan Sep 24 '18 at 20:25
  • @– user633183 Thanks for the Q&A, I found it helpful but it has some high level coding in it and also stated by the author. I understood it to almost half way until he started introducing some new methods and properties i'm not familiar with and yet to learn, also some libraries with the $ sign. I just started picking up JS and i want to go at my pace without rushing things up... Any additional help fro a beginner will surely help .. Thanks – OJay Sep 24 '18 at 23:32

1 Answers1

1

It's pretty straightforward, let's walk through this piece of code using the example in your questions.

console.log(deepEqual(obj, obj));

In the above case you're comparing the same object which in turn refers to same memory location, hence if (a === b) return true; gets executed and true is returned.

console.log(deepEqual(obj, {here: {is: "as"}, object: 3}));

In this example, since you're are comparing two different objects i.e, different memory locations therefore,

  1. a === b is false; now we move forward to compare the values of object keys.
  2. a == null... condition is also satisfied hence move forward
  3. keys length are same so we go inside the for loop
  4. for key = here obj.here is an object and keysB includes here; hence deepEqual(a[here], b[here]) is executed; and step 1 and 2 returns false
  5. Now inside for loop deepequal a["is"] == b["is"] which returns true.
  6. The same is repeated for a["object"] == b["object"] which is not true, but a == null ||... get's executed and hence returns false.

console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));

for this, all the steps in 2nd example get executed the same way buy in the 6th step a["object"] == b["object"] get's executed and hence you get true.

Hope this clears all the steps.

Roy
  • 471
  • 5
  • 15
  • Thanks Roy for the explanation .... But what about the second case?.. I just posted an updated task similar to the first one. Please take a look and explain to me how the loop can complete all its run without returning "true" for qual non object values on the first check or "false" on the second check. I think that will end the program without completing... I will really like to understand how this check really works.. Thanks – OJay Sep 24 '18 at 17:31
  • As I mentioned in the answer, 2nd example is returning false because of a["object"] != b["object"]; deepEqual(a["is"], b["is"])) will return true only as the first condition itself get's satisfied. – Roy Sep 25 '18 at 03:07
  • 1
    And regarding "wont that stop the function from completing the check for the remaining properties?" no it won't because for the console logs calling deepEqual, they will be listenling to the return of the function invoked by it. and recursive deepEqual called within the parent will only return value to it's parent. Thus, in the parent deepEqual will finally return false based on "if (!keysB.includes('object') || !deepEqual(a['object'], b['object'])) return false;" – Roy Sep 25 '18 at 03:11