JS Recursive object assign [duplicate]
Asked Answered
S

1

12

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.

Shovel answered 9/4, 2018 at 6:32 Comment(9)
"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 doesn't work as you expect? Example: jsfiddle.net/9oczv2a0Antiquate
@T.J.Crowder give me a couple of minutes to show you.Shovel
Can you also indicate the expected results for oldObject.params === newObject.params and oldObject === newObject ?Numbersnumbfish
oldObject.params === newObject.params // false oldObject === newObject // falseShovel
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?Antiquate
@T.J.Crowder as you can see it's not duplicate. Check this bin jsbin.com/wufalikovo/edit?js,outputShovel
So you're not going to answer the question?Antiquate
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.Shovel
Please edit your previous question instead of reposting it.Vaucluse
T
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

Trinatrinal answered 9/4, 2018 at 7:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.