简体   繁体   中英

Update nested JS objects without overwriting missing properties

EDIT: Thanks 4 all the great, diverse answers - I chose the solution that worked for me even after I realized that I needed more requirements: I also needed new properties to be added and for it to work with arrays in objects as well.

Here's what I wanna do: Update one object through another one.
Here are some constraints:

  • Only properties that the new object has should be updated (and that the original object also has), the other properties should remain unchanged, NOT DELETED
  • Nested objects should also be updated in the same way

My Problem is that I don't know how to easily do this for nested objects because typeof x === "object" also returns true for Date objects for example.

Here's what I got so far:

 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) && oObj.hasOwnProperty(prop)) { oObj[prop] = uObj[prop]; } } }; console.log(originalObj); updateOrignal(originalObj, updateObj) console.log(originalObj);

Currently my updated object looks like this:

{
  "dateCreated": "2021-02-10T23:00:00.000Z",
  "value": "100",
  "subObj": {
    "val": 90
  }
}

My goal:

{
  "dateCreated": "2021-02-10T23:00:00.000Z",
  "value": "100",
  "subObj": {
    "count": 55,
    "val": 90
  }
}

You could test the constructor of the values like this:

 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 && value.constructor === Object && patch[key]? updateOriginal(original[key], patch[key]): (original[key] = patch[key]); }); } updateOriginal(originalObj, updateObj); console.log(originalObj);

This is the solution you need (from https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6 ), actually you can search on google "deep merge" or "recursively merge two javascript objects"

I added ES6 sintax {...obj} to be sure to clone objects before merging them

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

You could use recursive approach with reduce method and for..in loop and also check if the type of object is Date . This solution will not work with arrays and also will not modify original data.

 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)

This is what worked for me in the past. You can clean it up a little and customize for your purposes but the idea is as follows:

 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) && 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 && typeof item === 'object' &&;Array.isArray(item)); } console,log(originalObj); mergeDeep(originalObj. updateObj); console.log(originalObj);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM