Как сравнить объекты и найти различия?

Есть два объекта и нужно сравнить их и узнать, в чём они отличаются.

Объекты выглядят так:

New Object:  {
  no: 123,
  print: '123',
  colorQty: 0,
  id: 602
} 
 Old Object:  {
  no: 123,
  print: '123',
  colorQty: 1,
  id: 602
}

Видно, что colorQty: 0, меняется на colorQty: 1,.

Не нужно сравнить их и узнать, что они равны через isEqual, нужно узнать, в чём они различны.
Как в таком случае сравнить объекты?
  • Вопрос задан
  • 579 просмотров
Решения вопроса 1
Мне кажется, такой вариант вам может подойти:
function generateJsonPatch(obj1, obj2) {
  const patch = [];

  // Рекурсивно обходим все свойства первого объекта
  for (const prop in obj1) {
    if (obj1.hasOwnProperty(prop)) {
      // Если свойство отсутствует во втором объекте, удаляем его
      if (!obj2.hasOwnProperty(prop)) {
        patch.push({op: "remove", path: `/${prop}`, oldVal: obj1[prop]});
      } else {
        // Если свойство является объектом или массивом, рекурсивно обходим его
        if (typeof obj1[prop] === "object") {
          patch.push(...generateJsonPatch(obj1[prop], obj2[prop]).map(p => {
            p.path = `/${prop}${p.path}`;
            return p;
          }));
        } else {
          // Если значение свойства отличается от значения во втором объекте, обновляем его
          if (obj1[prop] !== obj2[prop]) {
            patch.push({op: "replace", path: `/${prop}`, value: obj2[prop], oldVal: obj1[prop]});
          }
        }
      }
    }
  }

  // Обходим свойства второго объекта, которых нет в первом объекте
  for (const prop in obj2) {
    if (obj2.hasOwnProperty(prop) && !obj1.hasOwnProperty(prop)) {
      // Добавляем новое свойство
      patch.push({op: "add", path: `/${prop}`, value: obj2[prop], oldVal: undefined});
    }
  }

  return patch;
}

Вот что он выдаёт в вашем случае:
[ { op: 'replace', path: '/colorQty', value: 1, oldVal: 0 } ]


Код генерировал не я. Я попросил ChatGPT:
prompt и оригинальный ответ



Напиши функцию на javascript, которая принимает в себя два js-объекта или массива, на выходе я должен получить jsonpatch, который можно применить к первому объекту, чтобы получился объект идентичный второму

... вариант без oldValue ...

добавь ещё в каждую операцию jsonpatch и старое значение, чтобы при чтении было понятно, что на что заменяется

Вот обновлённый код функции generateJsonPatch с добавлением старого значения в каждую операцию jsonpatch:

function generateJsonPatch(obj1, obj2) {
  const patch = [];

  // Рекурсивно обходим все свойства первого объекта
  for (const prop in obj1) {
    if (obj1.hasOwnProperty(prop)) {
      // Если свойство отсутствует во втором объекте, удаляем его
      if (!obj2.hasOwnProperty(prop)) {
        patch.push({op: "remove", path: `/${prop}`, oldVal: obj1[prop]});
      } else {
        // Если свойство является объектом или массивом, рекурсивно обходим его
        if (typeof obj1[prop] === "object") {
          patch.push(...generateJsonPatch(obj1[prop], obj2[prop]).map(p => {
            p.path = `/${prop}${p.path}`;
            return p;
          }));
        } else {
          // Если значение свойства отличается от значения во втором объекте, обновляем его
          if (obj1[prop] !== obj2[prop]) {
            patch.push({op: "replace", path: `/${prop}`, value: obj2[prop], oldVal: obj1[prop]});
          }
        }
      }
    }
  }

  // Обходим свойства второго объекта, которых нет в первом объекте
  for (const prop in obj2) {
    if (obj2.hasOwnProperty(prop) && !obj1.hasOwnProperty(prop)) {
      // Добавляем новое свойство
      patch.push({op: "add", path: `/${prop}`, value: obj2[prop], oldVal: undefined});
    }
  }

  return patch;
}


Каждая операция jsonpatch теперь содержит поле `oldVal`, которое хранит старое значение свойства, которое было изменено. Если свойство было удалено или добавлено, то `oldVal` будет иметь значение `undefined`.

Пример использования:

const obj1 = {a: {b: "hello"}, c: [1, 2, 3]};
const obj2 = {a: {b: "world", d: "foo"}, c: [1, 2, 4, 5], e: "bar"};

const patch = generateJsonPatch(obj1, obj2);

console.log(patch);
// Output:
// [
//   {"op":"replace","path":"/a/b","value":"world","oldVal":"hello"},
//   {"op":"add","path":"/a/d","value":"foo","oldVal":undefined},
//   {"op":"remove","path":"/c/2","oldVal":3},
//   {"op":"add","path":"/c/3","value":5,"oldVal":undefined},
//   {"op":"add","path":"/e","value":"bar","oldVal":undefined}
// ]


Обратите внимание, что поле oldVal в jsonpatch содержит информацию только о тех свойствах, которые были изменены или удалены. Если свойство не было изменено, то его oldVal будет иметь значение undefined.



PS: сам удивился, на сколько он хорош в подобных задачах. Можно было бы написать и самому, точно также рекурсивно обойдя объекты, но эта шняга сэкономила достаточно много времени.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@WaterSmith
Android-разработчик. Java, Kotlin
Написать функцию, которая сравнит объекты через isEqual и если они отличаются, сравнит их непосредственно по полям, а в качестве результата выдаст список отличающихся полей. Или, например выдаст мапу содержащую все поля, в качестве ключей и значение true/false обозначающее, отличается поле или нет. Конкретная реализация сильно зависит от вашей задачи.
Ответ написан
mayton2019
@mayton2019
Bigdata Engineer
Блин. Распечатай их на экране и в среде разработки сравни через diff.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы