【问题标题】:Function checking for "deep equality" of nested objects检查嵌套对象的“深度相等”的函数
【发布时间】:2015-09-15 02:27:47
【问题描述】:

我正在尝试编写一个函数来检查两个对象是否具有相同的值。此功能要求我检查存储为原始对象内的值的任何对象的相等性。我开发的方法(见下面的代码)是首先检查非对象值的相等性。然后,如果这些都匹配,我再次遍历对象并对原始函数进行递归调用,这允许我比较两个对象的每个嵌套级别。

但是,这种方法仅部分有效。递归调用的性质意味着我只能在对象中的第一个键值对处检查嵌套对象的相等性。一旦比较了第一组嵌套对象并且递归调用返回,我无法弄清楚如何检查包含嵌套对象的任何其他键值对。这是函数:

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
}

我的基本问题是,我认为我需要一个递归调用来检查嵌套对象的深度相等性,但我只能成功执行一次此检查。有没有人试图解决这样的问题?如果您需要更具体的内容,我将提供特定对象的结果示例。谢谢!

【问题讨论】:

  • 您是说您不在乎属性名称吗?顺便说一句,for (i in val1) for (i in val2) 是灾难性的。
  • 我正在检查值。同意 for 循环不是最优的 - 请耐心等待,我是一个没有经验的程序员,这是我第一次解决这个问题
  • 所以您会期望{a:1, b:2}{a:2, b:1} 相等(因为它们包含相同的值)?
  • 您是否考虑过仅在两个对象上使用 JSON.stringify 并比较它们的字符串是否相等?不确切知道什么构成相等或对象的结构,我仅将其发布为评论。如果这种方法有任何价值,我将升级为答案。
  • 对不起,没有。我关心财产名称。我误解了你的第一个问题。例如,var val1 = {"city": "Seattle", "name": {"first": {"Ben": "Benny"}}, "country": "USA", "firstname": {"first": {"Ben": "Bedanny"}}} var val2 = {"city": "Seattle", "name": {"first": {"Ben": "Benny"}}, "country": "USA", "firstname": {"first": {"Ben": "Benny"}}} 应该返回 false,但它返回 true(因为永远不会检查第二组嵌套对象,因为如果第一组嵌套对象相同,则函数返回 true。

标签: javascript recursion javascript-objects deepequals


【解决方案1】:

这是一种可能的解决方案,但我建议您找到自己的解决方案,真的。

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
}

您不仅需要检查obj1 中的所有内容是否存在于obj2 中,还要检查obj2 中的所有内容是否存在于obj1 中。此解决方案需要两种方式进行比较,但您可以大大优化。

还有一些测试用例

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))

【讨论】:

  • 感谢您这样做——我对问题的指示是在一个函数中执行此操作——但这​​绝对是有道理的。感谢您为此所做的工作!
  • 多么可怕的指令......这不是你想要的编码方式,yuch。
【解决方案2】:

您可能想要的是来自lodashunderscore 库的_.isEqual

还有来自Chai.js 断言库的deepEqual 测试。

【讨论】:

    【解决方案3】:

    一个简单的解决方案是对对象进行 JSON 字符串化并比较它们的字符串表示。正如@Jan 提到的......

    这仅在对象以完全相同的方式初始化时才有效 大大地。如果属性相同但顺序不同,它将 失败

    ...这有点脆弱,但可能适合您的目的。

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      • 1970-01-01
      • 2018-11-30
      相关资源
      最近更新 更多