Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS Recursive object assign [duplicate]

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.

like image 635
undefined Avatar asked Apr 09 '18 06:04

undefined


People also ask

Is object assign a deep copy?

By using Object. assign() , you are actually doing Shallow Copy of your object. Whenever we do an operation like assigning one object to other, we actually perform a shallow copy, i.e. if OBJ1 is an object, modifying it through another object which is OBJ2 will reflect changes in OBJ1 too.

Does object assign overwrite?

Object. assign() returns a target object. In case of a name collision between a source and target property, Object. assign() will overwrite the local property of the target object.

How to assign one object to another object in JavaScript?

var clone = Object. assign({}, obj); The Object. assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.


1 Answers

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

like image 190
Matt Way Avatar answered Sep 19 '22 13:09

Matt Way