JS Recursive object assign

undefined picture undefined · Apr 9, 2018 · Viewed 8.2k times · Source

I learned that when using Object.assign() it extends only the top level object. How can I deeply extend the object? For example, let's say I have the following source object:

const source = {
  id: 1,
  otherKey: {},
  params: {
    page: {
      a: 1,
      b: {}
    },
    data: {
      b: 1
    }
  }
}

And I am using Object.assign() like this:

Object.assign({}, source, {
  params: {
    page: {
      a: 2
    }
  }
}

The result will be:

{
      id: 1,
      otherKey: {},
      params: {
        page: {
          a: 2
        }
      }
}

How can I preserve the params.data key and the params.page.b key in a shallow clone way.

oldObject.params.data === newObject.params.data  // true
oldObject.params.page === newObject.params.page  // false
oldObject.params.page.b === newObject.params.page.b // true

Note: This question is not the same as How to deep merge instead of shallow merge. The answers there does not give the expected results.

Check this bin that takes an answer from the above link.

Answer

Matt Way picture Matt Way · Apr 9, 2018

So in your posted code, what happens is, if the source and target both contain the same key then nothing happens. The object is recursed down to the children. However if you simply change the inner block to this:

if (!target[key]) { 
  Object.assign(target, { [key]: {} });
}else{          
  target[key] = Object.assign({}, target[key])
}
mergeDeep(target[key], source[key]);

This will create a new assigned object for any key that is found in both the source and the target. Interestingly though, if you do this, your expected falseys will not show up in the console. This is because the target will always match the result, as it is the final mutated object. So in order to get your expected false results, you need to do something like the following:

var tester = source.params
const result = mergeDeep(source, b)
console.log(tester === result.params) // this will be false after the above addition

You can see your desired result here: http://jsbin.com/vicemiqiqu/1/edit?js,console