Merge two objects without override

Viewed 22643

I have a defaultObject like that:

var default = {
    abc: "123",
    def: "456",
    ghi: {
       jkl: "789",
       mno: "012"
    }
};

And I have another like:

var values = {
    abc: "zzz",
    ghi: {
       jkl: "yyy",
    }
};

How can I merge those 2 objects with the following result (no override)?

var values = {
    abc: "zzz",
    def: "456",
    ghi: {
       jkl: "yyy",
       mno: "012"
    }
};

(I don't want to change the default object!)

6 Answers

My version based on Oriol's answer adds a check for arrays, so that arrays don't get transformed into funny {'0': ..., '1': ...} thingys

function extend (target) {
  for(var i=1; i<arguments.length; ++i) {
    var from = arguments[i];
    if(typeof from !== 'object') continue;
    for(var j in from) {
      if(from.hasOwnProperty(j)) {
        target[j] = typeof from[j]==='object' && !Array.isArray(from[j])
          ? extend({}, target[j], from[j])
          : from[j];
      }
    }
  }
  return target;
}

I found that the easiest way to to this is to use mergeWith() from lodash ( https://lodash.com/docs/4.17.15#mergeWith ) which accepts a customizer function that decides what to do with every property merge. Here is one that is recursive :

const mergeFunction = (objValue, srcValue) => {
  if (typeof srcValue === 'object') {
    _.mergeWith(objValue, srcValue, mergeFunction)
  } else if (objValue) {
    return objValue
  } else {
    return srcValue
  }
}
Related