admin管理员组

文章数量:1319466

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

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
  }
}
Share Improve this question edited Jan 21, 2021 at 11:43 Cold_Class asked Jan 20, 2021 at 21:04 Cold_ClassCold_Class 3,5046 gold badges51 silver badges92 bronze badges 4
  • 1 updateObj.hasOwnProperty(prop) <= should use uObj. Probably not the issue, but it is inconsistent. – Taplar Commented Jan 20, 2021 at 21:08
  • Your logic is checking if the update object and the original object have the key to update. I understand you don't want to delete keys, but if you require the key to be pre existing in both places, you're never going to add new ones. – Taplar Commented Jan 20, 2021 at 21:09
  • @Taplar thx, I corrected it – Cold_Class Commented Jan 21, 2021 at 8:50
  • @Taplar I didn' say I want to add new ones, and I don't. But also didn't say that I don't want it, so I get your point, updated my question^^ – Cold_Class Commented Jan 21, 2021 at 8:51
Add a ment  | 

4 Answers 4

Reset to default 4

This is the solution you need (from https://gist.github./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 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);

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

本文标签: javascriptUpdate nested JS objects without overwriting missing propertiesStack Overflow