Проверка функций на "глубокое равенство" вложенных объектов

Я пытаюсь написать функцию, которая проверяет, имеют ли два объекта одинаковые значения. Эта функция требует, чтобы я проверял равенство любых объектов, которые хранятся как значения внутри исходных объектов. Подход, который я разработал (см. Код ниже), заключается в том, чтобы сначала проверить равенство необъектных значений. Затем, если все они совпадают, я снова перебираю объекты и выполняю рекурсивный вызов исходной функции, что позволяет мне сравнивать каждый вложенный уровень двух объектов.

Однако этот подход работает только частично. Природа рекурсивного вызова означает, что я могу проверить только равенство вложенных объектов в первой паре ключ-значение в объекте. Я не могу понять, как проверить какие-либо дополнительные пары ключ-значение, содержащие вложенные объекты, после сравнения первого набора вложенных объектов и возврата рекурсивного вызова. Вот функция:

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
}

Моя основная проблема в том, что я считаю, что мне нужен рекурсивный вызов для проверки глубокого равенства вложенных объектов, но я могу выполнить эту проверку только один раз. Кто-нибудь пытался решить такую ​​проблему? Я приведу примеры моих результатов для конкретных объектов, если вам нужно более конкретное. Спасибо!

3 ответа

Решение

Простое решение состоит в том, чтобы JSON структурировал объекты и сравнил их строковые представления. Как @Jan упоминает...

это будет работать, только если объекты инициализируются точно так же. Если свойства одинаковы, но в другом порядке, произойдет сбой

... это немного ломко, но может удовлетворить ваши цели.

Вот одно из возможных решений, но я действительно рекомендую найти свое.

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

То, что вы, вероятно, хотите _.isEqual от lodash или же underscore библиотека.

Также есть deepEqual тест из Chai.js библиотека утверждений.

Другие вопросы по тегам