#javascript
#javascript
Вопрос:
РЕДАКТИРОВАТЬ: Спасибо 4 всем замечательным, разнообразным ответам — я выбрал решение, которое сработало для меня даже после того, как я понял, что мне нужно больше требований: мне также нужно было добавить новые свойства, а также для работы с массивами в объектах.
Вот что я хочу сделать: обновить один объект с помощью другого.
Вот некоторые ограничения:
- Должны быть обновлены только свойства, которые есть у нового объекта (и которые также есть у исходного объекта), остальные свойства должны оставаться неизменными, А НЕ УДАЛЯТЬСЯ
- Вложенные объекты также должны обновляться таким же образом
Моя проблема в том, что я не знаю, как легко сделать это для вложенных объектов, потому typeof x === "object"
что также возвращает true, например, для объектов даты.
Вот что я получил до сих пор:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
let updateOrignal = (oObj, uObj) => {
for (let prop in uObj) {
if (uObj.hasOwnProperty(prop) amp;amp;
oObj.hasOwnProperty(prop)) {
oObj[prop] = uObj[prop];
}
}
};
console.log(originalObj);
updateOrignal(originalObj, updateObj)
console.log(originalObj);
В настоящее время мой обновленный объект выглядит следующим образом:
{
"dateCreated": "2021-02-10T23:00:00.000Z",
"value": "100",
"subObj": {
"val": 90
}
}
Моя цель:
{
"dateCreated": "2021-02-10T23:00:00.000Z",
"value": "100",
"subObj": {
"count": 55,
"val": 90
}
}
Комментарии:
1.
updateObj.hasOwnProperty(prop)
<= следует использоватьuObj
. Вероятно, это не проблема, но она несовместима.2. Ваша логика проверяет, есть ли у объекта обновления и исходного объекта ключ для обновления. Я понимаю, что вы не хотите удалять ключи, но если вам требуется, чтобы ключ уже существовал в обоих местах, вы никогда не добавите новые.
3. @Taplar спасибо, я исправил это
4. @Taplar Я не говорил, что хочу добавить новые, и я этого не делаю. Но также не сказал, что я этого не хочу, поэтому я понял вашу точку зрения, обновил свой вопрос ^^
Ответ №1:
Это то решение, которое вам нужно (из https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6 ), на самом деле вы можете выполнить поиск в Google «глубокое слияние» или «рекурсивное слияние двух объектов javascript».
Я добавил ES6 sintax { …obj} чтобы обязательно клонировать объекты перед их объединением
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
const merge = (target, source) => {
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
for (const key of Object.keys(source)) {
if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key]))
}
// Join `target` and modified `source`
Object.assign(target || {}, source)
return target
}
console.log(merge({ ...originalObj}, {...updateObj}));
Ответ №2:
Вы можете протестировать конструктор значений следующим образом:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
let updateOriginal = (original, patch) => {
Object.entries(patch).forEach(([key, value]) => {
value amp;amp; value.constructor === Object amp;amp; patch[key]
? updateOriginal(original[key], patch[key])
: (original[key] = patch[key]);
});
}
updateOriginal(originalObj, updateObj);
console.log(originalObj);
Ответ №3:
Вы можете использовать рекурсивный подход с reduce
методом и for..in
циклом, а также проверить, соответствует ли тип объекта Date
. Это решение не будет работать с массивами, а также не будет изменять исходные данные.
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
function update(o1, o2) {
return Object.entries(o1).reduce((r, e) => {
for (let p in o2) {
if ([o1[p], o2[p]].every(o => typeof o === 'object')) {
r[p] = o2[p] instanceof Date ? o2[p] : update(r[p], o2[p])
} else {
r[p] = o2[p]
}
}
return r
}, { ...o1 })
}
const result = update(originalObj, updateObj)
console.log(result)
Ответ №4:
Это то, что работало для меня в прошлом. Вы можете немного очистить его и настроить для своих целей, но идея заключается в следующем:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
function mergeDeep(target, source) {
if (isObject(target) amp;amp; isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) {
Object.assign(target, { [key]: {} });
}
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
}
function isObject(item) {
return (item amp;amp; typeof item === 'object' amp;amp; !Array.isArray(item));
}
console.log(originalObj);
mergeDeep(originalObj, updateObj);
console.log(originalObj);