Мне кажется, такой вариант вам может подойти:
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: сам удивился, на сколько он хорош в подобных задачах. Можно было бы написать и самому, точно также рекурсивно обойдя объекты, но эта шняга сэкономила достаточно много времени.