Function checking for “deep equality” of nested objects

陌路散爱 提交于 2019-12-13 02:38:21

问题


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!


回答1:


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.




回答2:


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:


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

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



来源:https://stackoverflow.com/questions/31101894/function-checking-for-deep-equality-of-nested-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!