11

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.

undefined
  • 6,366
  • 12
  • 46
  • 90
  • 1
    *"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."* It looks exactly like a duplicate. What specifically about (for instance) [this answer](https://stackoverflow.com/a/34749873/157247) doesn't work as you expect? Example: https://jsfiddle.net/9oczv2a0/ – T.J. Crowder Apr 09 '18 at 06:34
  • @T.J.Crowder give me a couple of minutes to show you. – undefined Apr 09 '18 at 06:36
  • Can you also indicate the expected results for `oldObject.params === newObject.params` and `oldObject === newObject` ? – klugjo Apr 09 '18 at 06:37
  • oldObject.params === newObject.params // false oldObject === newObject // false – undefined Apr 09 '18 at 06:38
  • So you want something that will use the same, preexisting `params` object between the source and destination. That's probably not a good idea, but if it's what you want to do, surely it's simple enough to modify the code there to do that? Where are you stuck? – T.J. Crowder Apr 09 '18 at 06:41
  • @T.J.Crowder as you can see it's not duplicate. Check this bin http://jsbin.com/wufalikovo/edit?js,output – undefined Apr 09 '18 at 06:44
  • So you're not going to answer the question? – T.J. Crowder Apr 09 '18 at 06:58
  • This is where I'm stuck, I don't know how to convert the code in the jsbin to output the expected result. I need help. – undefined Apr 09 '18 at 07:00
  • Please [edit] your [previous question](https://stackoverflow.com/q/49719892/1048572) instead of reposting it. – Bergi Apr 09 '18 at 10:59

1 Answers1

5

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

Matt Way
  • 32,319
  • 10
  • 79
  • 85