Function checking for “deep equality” of nested ob

2019-08-11 09:01发布

I am trying to write a function that checks if two objects have the same values. This function requires that I check for the equality of any objects that are stored as values inside the original objects. The approach I have developed (see code below) is to first check the equality of non-object values. Then, if these all match, I iterate over the objects again and make a recursive call to the original function, which allows me to compare each nested level of the two objects.

However, this approach only partially works. The nature of the recursive call means I can only check the equality of nested objects at the first key - value pair in the object. I cannot figure out how to check any additional key-value pairs containing nested objects once the first set of nested objects have been compared and the recursive call returns. Here is the function:

var deepEqual = function(val1, val2) {
  if (typeof val1 === 'object' && typeof val2 === 'object') {
      for (i in val1) {
        for (i in val2){
          if (typeof val1[i] !== 'object' && typeof val2[i] !== 'object') {
            if (val1[i] !== val2[i]) {
              return false
            }
          }
        }
      }
      for (i in val1) {
        for (i in val2){
          if (typeof val1[i] === 'object' && typeof val2[i] === 'object') {
            return deepEqual(val1[i], val2[i])
          }
        }
      }
    return true
  }
  else if (val1 === val2) {
    return true
  }
  else return false
}

My basic problem is that I believe I need a recursive call to check for the deep equality of nested objects, but that I can only do this check once successfully. Has anybody tried to solve a problem like this? I'll provide examples of my results for specific objects if you need more specific. Thanks!

3条回答
再贱就再见
2楼-- · 2019-08-11 09:26

Here's one possible solution, but I recommend you find your own, really.

function isEqual(var1, var2) { // Break the comparison out into a neat little function
  if (typeof var1 !== "object") {
    return var1===var2;
  } else {
    return deepEqual(var1, var2);
  }
}

function deepEqual(var1, var2) {
   for (i in var1) { 
      if(typeof var2[i] === "undefined") { // Quick check, does the property even exist?
         return false;
      }
      if (!isEqual(var1[i], var2[i])) {
         return false;
      }
   }
   return true;
}

function areObjectsEqual(obj1, obj2) {
   return deepEqual(obj1, obj2) && deepEqual(obj2, obj1); // Two-way checking
}

You not only need to check if everything in obj1 exists in obj2, but also that everything in obj2 exists in obj1. This solution entails doing the comparison both ways, but you could optimize this greatly.

And some test cases

var v1 = { obj0:"jan", obj:{ name:"jan"}, obj2:"ben" }
var v2 = { obj:{ name:"jan"}, obj2:"ben" }

console.log(areObjectsEqual(v1, v2))

v1 = { obj:{ name:"jan"}, obj2:"ben" }
v2 = { obj:{ name:"jan"}, obj2:"ben" }

console.log(areObjectsEqual(v1, v2))

v1 = { obj:{ name:"jan2"}, obj2:"ben" }
v2 = { obj:{ name:"jan"}, obj2:"ben" }

console.log(areObjectsEqual(v1, v2))

v1 = { obj:{ name:"jan"}, obj2:"ben" }
v2 = { obj:{ name:"jan"}, obj2:"ben", obj3:"pig" }

console.log(areObjectsEqual(v1, v2))
查看更多
甜甜的少女心
3楼-- · 2019-08-11 09:31

A simple solution would be to JSON stringify the objects and compare their string representations. As @Jan mentions ...

this will only work if the objects are initialized in the exact same way. If the properties are the same but in a different order, it will fail

...this is a bit brittle but may suit your purposes.

查看更多
SAY GOODBYE
4楼-- · 2019-08-11 09:42

What you probably want is _.isEqual from the lodash or underscore library.

There is also the deepEqual test from the Chai.js assertion library.

查看更多
登录 后发表回答