简体   繁体   中英

deep merge with concatenating arrays in javascript

I want to deep merge 2 javascript objects with similar properties in a reducer. The catch is the two objects have arrays as their properties and I need them to be concatenated instead of replaced. Basically something like this:

var x = {
  name: 'abc',
  family: {
    children: [
      {name: 'xxx'},
      {name: 'zzz'}
    ]
  }
};

var y = {
  name: 'abc',
  family: {
    children: [
      {name: 'yyy'}
    ]
  }
};

will result on

var y = {
  name: 'abc',
    family: {
      children: [
        {name: 'xxx'}, {name: 'zzz'}, {name: 'yyy'}
      ]
    }
  };

any suggestion? I prefer lodash based solution if possible. Also, since it's in reducer, I cannot just replace the property with new object

objects have arrays as their properties and I need them to be concatenated instead of replaced

For your simple example it would be enough to use Array.prototype.concat() function:

 var x = {name: 'abc', family:{children:[{name: 'xxx'}, {name: 'zzz'} ] }}, y = {name: 'abc', family: {children: [{name: 'yyy'}]}}; y.family.children = y.family.children.concat(x.family.children); console.log(y); 

If you're already using lodash, check if mergeWith doesn't do what you want... (see this so answer for example).

Anyway here is a quick function that should do what you want. Be warned that it does very little in terms of checking, and only merges properties that are in the first object (since you said that your objects are similar).

Also it doesn't mutate the objects but instead creates a new one.

 function merge(a, b){ var ret = {}; for(prop in a){ //assume b doesn't have properties that a hasn't //only merge on similar types, else keep a var propA = a[prop], propB = b[prop]; console.log(prop, typeof propA) if( (typeof propA == typeof propB) && (typeof propA == "object")){ if(Array.isArray(propA)){ ret[prop] = propA.concat(propB); }else{ ret[prop] = merge(propA, propB); } }else{ ret[prop] = propA; } } return ret; } var x = { name: 'abc', family: { children: [ {name: 'xxx'}, {name: 'zzz'} ] } }; var y = { name: 'abc', family: { children: [ {name: 'yyy'} ] } }; console.log(merge(x, y)); console.log(merge(y, x)); 

I assume one of your objects is the state you want to change in your reducer.

What about:

return Object.assign({}, x, {
   family: [...x.family, ...y.family]
  })

First this creates a new empty object and assigns x ( your old state ) to it. Afterwards it assigns the family which it overrides in the new object. The ... represents all elements in an array, so this can be used to concat the arrays.

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