3

I've seen this post and was wondering if there was a way of using javascript to write a function that could conditionally update all properties of an object by using another object with the new values?

Say I have this object:

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };

And I want to update its values using the properties passed by another object like this:

let newObj = {test2: 'newValue2'}

In this case I just want to update property "test2". If I know the properties I want to update and I know the original properties beforehand, I'll use:

oldObj = {
  ...(newObj.test1) && {test1: newObj.test1} || {test1: oldObj.test1},
  ...(newObj.test2) && {test2: newObj.test2} || {test2: oldObj.test2},
  ...(newObj.test3) && {test3: newObj.test3} || {test3: oldObj.test3},
};

Meaning I will only update the value if the property comes in the new object, but of course I would have to add as many conditions as there are properties in the object.

This approach is fine, but it's not generalised so if the object has 10 properties, I would have to write 10 conditions.

Is there a way of writing a function that could conditionally update the properties so that I don't have to write the 10 (or more) conditions?

c-chavez
  • 7,237
  • 5
  • 35
  • 49
  • How about looping over all the properties in the json and checking for matches from the `newJson´?? – Exception_al Feb 12 '18 at 14:45
  • 3
    There is no JSON in your question, I suggest different variable names. JSON is a *textual notation* for data exchange. [(More here.)](http://stackoverflow.com/a/2904181/157247) If you're dealing with JavaScript source code, and not dealing with a *string*, you're not dealing with JSON. – T.J. Crowder Feb 12 '18 at 14:45
  • I think you are looking for objects merging (Not sure), take a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – Hyyan Abo Fakher Feb 12 '18 at 14:45
  • Since your title is asking about *updating* a property, not creating one in a new object, why not just use `Object.assign`? – Bergi Feb 12 '18 at 14:48
  • You *definitely* should have simplified and corrected that to `jsonObj = { test1: newJson.test1 ? newJson.test1: jsonObj.test1, test2: newJson.test2 ? newJson.test2 : jsonObj.test2, test3: newJson.test3 ? newJson.test3: jsonObj.test3, };` Don't use object literals inside spread syntax, and don't use short-circuiting `||` and `&&` instead of the conditional operator! – Bergi Feb 12 '18 at 14:52
  • 3
    Clarify something: if `newJson` had a property called "xyz", do you want to ignore that (because there's no "xyz" property in `jsonObj`), or do you want the set of all properties from both source objects in the result? – Pointy Feb 12 '18 at 14:52
  • @T.J.Crowder ok, changed the question. – c-chavez Feb 12 '18 at 15:19
  • @Exception_al I've thought of that, but was looking for an alternative. – c-chavez Feb 12 '18 at 15:20
  • 2
    @HyyanAboFakher exactly what I was looking for! thanks! – c-chavez Feb 12 '18 at 15:22
  • @Pointy I will only update properties that exist in the old object, new properties that don't exist in the old object will not be added. – c-chavez Feb 12 '18 at 15:23

1 Answers1

8

In a comment you've said:

I will only update properties that exist in the old object, new properties that don't exist in the old object will not be added.

That means we have to leave spread syntax and Object.assign out of the picture, as both of them would copy all properties from newObj over to oldObj.

Instead, we can use a simple loop (and if this comes up a lot, you can create a function, perhaps updateObject):

for (const key of Object.keys(newObj)) {
  if (key in oldObj) {
    oldObj[key] = newObj[key];
  }
}

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };
let newObj = {test2: 'newValue2', xyz: "don't copy me"};

for (const key of Object.keys(newObj)) {
  if (key in oldObj) {
    oldObj[key] = newObj[key];
  }
}
console.log(oldObj);

(You may prefer oldObj.hasOwnProperty(key) instead of key in oldObj, depending on your rules for updating.)

Or using the relatively-new Object.entries and some destructuring:

for (const [key, value] of Object.entries(newObj)) {
  if (key in oldObj) {
    oldObj[key] = value;
  }
}

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };
let newObj = {test2: 'newValue2', xyz: "don't copy me"};

for (const [key, value] of Object.entries(newObj)) {
  if (key in oldObj) {
    oldObj[key] = value;
  }
}
console.log(oldObj);

Before the clarification quoted above, I'd posted the following about spread and Object.assign. Just for completeness, but they don't apply to your case where you want to skip properties that oldObj doesn't have:

You don't have to be anything like that complicated with the spread syntax, just:

oldObj = {...oldObj, ...newObj};

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };
let newObj = {test2: 'newValue2', xyz: "I get copied too"};

oldObj = {...oldObj, ...newObj};
console.log(oldObj);

That will create a new object with all of oldObj's and newObj's properties, with newObj's properties winning if both have the same name.

Note that property spread is brand-new, just approved to Stage 4 (will be in the ES2018 spec). If you don't want to use a Stage 4 proposal, use Object.assign:

oldObj = Object.assign({}, oldObj, newObj);

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };
let newObj = {test2: 'newValue2', xyz: "I get copied too"};

oldObj = Object.assign({}, oldObj, newObj);
console.log(oldObj);

You'd also use Object.assign if you want to update oldObj in-place instead of creating a new object:

Object.assign(oldObj, newObj);

let oldObj = {test1: 'valueTest1',test2: 'valueTest2',test3: 'valueTest3' };
let newObj = {test2: 'newValue2', xyz: "I get copied too"};

Object.assign(oldObj, newObj);
console.log(oldObj);

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    The only thing is that this will pick up *all* properties from `newJson`, but my reading of the OP suggests that maybe that's not what's desired. – Pointy Feb 12 '18 at 14:49
  • Well for example it's not clear what should happen if `newJson` has a property called "xyz". Should that be in the result object or not? – Pointy Feb 12 '18 at 14:51
  • @Pointy: That *seems* to be the goal (weird not to show unrelated properties in the example otherwise). I just went and posted a comment asking -- then deleted it when yours appeared! :-) – T.J. Crowder Feb 12 '18 at 14:53
  • 1
    @Pointy: I've covered my bases now, just in case. :-) – T.J. Crowder Feb 12 '18 at 14:56
  • 1
    In my case Object.assign(jsonObj, newJson); did the trick. I had already used the "hasOwnProperty" function and loop, but was looking for an alternative. Keep in mind that If the new object has new properties they will get added using this approach. I'm validating that before so I don't have that problem. – c-chavez Feb 12 '18 at 15:27
  • 2
    @c-chavez: Yup. When I saw your comment, I reordered the answer to put the versions that don't do that up top (and to rename the variables). – T.J. Crowder Feb 12 '18 at 15:35