skip to Main Content

I’d like to merge two objects together, but in a way that preserves children at any depth.

For example:

const base = {
    a: {
        i: {
            foo: true
        }
    }
};

const add = {
    a: {
        j: {
            foo: false
        }
    },
    b: true
};

const result = {...base, ...add};
console.log(result);

Printed result:

{
    a: {
        j: {
            foo: false
        }
    },
    b: true
}

Ideally, the result would be

{
    a: {
        i: {
            foo: true
        }
        j: {
            foo: false
        }
    },
    b: true
}

Is there a way to… I’m gonna call it "zipper merge" the two objects?

This is for a redux data reducer. I’m going to use null (or a different reducer) to delete if I need to.

3

Answers


  1. You could define a function that recursively merges any number of objects like so:

    const base={a:{i:{foo:!0}}},add={a:{j:{foo:!1}},b:!0};
    // Note: if multiple objects define a value for the same (nested) key, the
    // value in the result will be its value in the last object defining that key
    function deepMerge(...objs) {
      const res = {};
      const helper = (o, r = res) => 
        Object.entries(o).forEach(([k, v]) => 
          typeof v === 'object' && v !== null ? helper(v, r[k] ??= {}) :
            r[k] = v);
      objs.forEach(o => helper(o));
      return res;
    }
    console.log(deepMerge(base, add));
    Login or Signup to reply.
  2. Lodash has such a function.

    _.merge(object, other);
    // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
    
    Login or Signup to reply.
  3. This is the deep merge function I use for redux in my applications. For most use cases, merging arrays doesn’t make sense. So my merge fn overwrites when the incoming value is an array

    export const deepMerge = (obj1, obj2 = {}) => {
      const recursiveMerge = (obj, entries) => {
        for (const [key, value] of entries) {
          if (value && typeof value === 'object' && !Array.isArray(value)) {
            obj[key] = obj[key] ? { ...obj[key] } : {}
            recursiveMerge(obj[key], Object.entries(value))
          } else {
            obj[key] = value
          }
        }
        return obj
      }
    
      return { ...recursiveMerge(obj1, Object.entries(obj2)) }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search