简体   繁体   中英

javascript Object.assign() without overriding fields

Is there any way to merge two objects, like Object.assign(a, b) , but I want the same field in a keeps its origin value (without overriding from b ).

a = {x: 1, y: 2}
b = {y: 3, z: 4}

Object.assign(a, b)
// Now we get a = {x: 1, y: 3, z: 4}, so what if I want {x: 1, y: 2, z: 4}?
console.log(a) 

Note: thanks for the efforts from the answers, the key requirements for the question is:

  1. modify a
  2. not too much code
  3. not too slow

To modify the a reference (like you seem to be wanting to do from your example), you could do:

 const a = {x: 1, y: 2}; const b = {y: 3, z: 4}; Object.assign(a, {...b, ...a}); console.log(a);

This essentially says, replace the overlapping properties in b with those from a , and then merge this replaced object into a .

Above, the {...b, ...a} first merges a with b , so a overwrites properties in b , giving us:

{y: 3, z: 4, x: 1, y: 2}
// evalutes to
{z: 4, x: 1, y: 2}

Now we merge this result into a with the Object.assign() call:

{x: 1, y: 2, z: 4, x: 1, y: 2}
// evalutes to
{z: 4, x: 1, y: 2}
// ie:
{x: 1, y: 2, z: 4}

Edit: To meet your requirements, use a regular for...in loop, it's efficient, doesn't require much code (especially if you remove the blocks), and modifies a :

 const a = {x: 1, y: 2}; const b = {y: 3, z: 4}; for(const key in b) a[key] ??= b[key]; console.log(a); // {"x": 1, "y": 2, "z": 4}

The above works if your values won't be nullish ( null / undefined ) as it uses logical nullish assignment ( ??= ), otherwise, you can replace the assignment with:

a[key] = key in a ? a[key] : b[key]; 

The best solution to this is to avoid using Object.assign and use spread operator as by doing so you'll achieve your goal with simple logic. In spread operator, the rightmost element overwrites the left one.

a = {x: 1, y: 2};
b = {y: 3, z: 4};
        
result = {...b, ...a}; 
result2 = {...a, ...b};
console.log(result); // {x: 1, y: 2, z: 4} 
console.log(result2); // {x: 1, y: 3, z: 4} 

//if you don't want to create new object and just modify a then
Object.assign(a, {...b, ...a});
console.log(a); // {x: 1, y: 2, z: 4} 

 let a = { x: 1, y: 2 }; let temp = { ...a }; let b = { y: 3, z: 4 }; Object.assign(a, b); Object.assign(a, temp); console.log(a);

You could use Object.entries and filter out keys that are already in a .

eg.

 a = {x: 1, y: 2} b = {y: 3, z: 4} //Object.assign(a, b) // Now we get a = {x: 1, y: 3, z: 4}, so what if I want {x: 1, y: 2, z: 4}? Object.assign(a, Object.fromEntries( Object.entries(b). filter(([k])=>!(k in a)))); console.log(a)

Finally I found the perfect solution is lodash.defaults .

https://lodash.com/docs/4.17.15#defaults

import _ from 'lodash'

a = {x: 1, y: 2}
b = {y: 3, z: 4}

_.defaults(a, b)

// Outputs {x:1, y:2, z:4}, perfectly as expected.
console.log(a) 

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