0

Orignal object is changing if cloned object is changed

const original = {
    "appList": [{
        "appId": "app-1",
        "serviceList": [{
            "service": "service-1",
            "mList": ["somedata"]
        },{
            "service": "service-2",
            "mList": []
        },{
            "service": "service-3",
            "mList": []
        }]
    }]
}
const clone = Object.assign({}, original);

Trying to do below change

clone.appList = clone.appList.filter(app => app.appId == 'app-1').map( app => {
  let serviceList = [...app.serviceList];
  if(app.serviceList && app.serviceList.length) {
    app.serviceList = serviceList.filter(service => {
      const { mList } = service;
      return mList && mList.length;
    });
  }
  return app;
}
);

when logging original object also changed

console.log(clone);
console.log(original);
kiranbabu
  • 95
  • 1
  • 5
  • 2
    `clone` is not a deep copy, only a shallow one. – evolutionxbox Aug 17 '21 at 19:49
  • 1
    It's because this is a shallow copy, no deep copy. `Object.assign` only creates a new object with the first layer of the object properties. It's not trivial to deep copy an object. The easiest way for simple objects is to use JSON. Stringyfy and parse. Check out the web and StackOverflow. Because this topic is nothing new. Search with keywords like `deep copy object`. – Domske Aug 17 '21 at 19:50
  • 2
    You never create a copy of the `app` objects, you only mutate them by assigning a new `.serviceList` to each. – Bergi Aug 17 '21 at 20:04
  • const clone = JSON.parse(JSON.stringify(object)); Did you try that? – bogdan ioan Sep 15 '21 at 20:06

2 Answers2

0

This is talked about in MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Assign only copies properties from the source to target object and if the source value is an object it copies the reference, hence a shallow copy.

Perhaps use lodash and the deepClone() method.

const clone = _.cloneDeep(original);
CodeoftheWarrior
  • 311
  • 2
  • 12
0

As many people here mentioned you need a deep copy of your Object.

There is a deep copy methode in V8 that is currently only available in NodeJS and might soon become available in Browsers but if your script runs in a Browser you can not use it as of now:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Then there is are hacky ways to do that in modern browsers, this method will not work with functions and can be bit slow but gets the job done, like this one:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

And finaly there are libraries that offer deep cloning, if you are already using lodash or jquery, then you are in luck as they come with this funcionallity build in, if not there is a library called just-clone which only offers deep cloning, so you don't have to add a full blown library to your project.

jQuery (https://api.jquery.com/jQuery.extend/):

jQuery.extend(true, { }, oldObject);

lodash (https://lodash.com/docs/#cloneDeep):

_.cloneDeep(oldObject);

just-clone (https://github.com/angus-c/just/tree/master/packages/collection-clone):

clone(oldObject);

There are great Answers on another related questions that might interest you for more information:

https://stackoverflow.com/a/122704/13987708

Or

https://stackoverflow.com/a/10916838/13987708

Christian
  • 427
  • 3
  • 7