【问题标题】:original object is changing if copy of a object is changed如果对象的副本发生更改,则原始对象正在更改
【发布时间】:2021-10-19 16:59:29
【问题描述】:

如果克隆对象发生变化,原始对象也会发生变化

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);

尝试做以下改变

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;
}
);

当记录原始对象时也改变了

console.log(clone);
console.log(original);

【问题讨论】:

  • clone 不是深拷贝,只是浅拷贝。
  • 因为这是浅拷贝,没有深拷贝。 Object.assign 只创建一个具有第一层对象属性的新对象。深度复制对象并非易事。简单对象最简单的方法是使用 JSON。 Stringyfy 和解析。查看网络和 StackOverflow。因为这个话题并不新鲜。使用 deep copy object 等关键字进行搜索。
  • 您永远不会创建app 对象的副本,您只能通过为每个对象分配一个新的.serviceList 来改变它们。
  • const clone = JSON.parse(JSON.stringify(object));你试过了吗?

标签: javascript arrays object ecmascript-6 ecmascript-5


【解决方案1】:

这在 MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 中有讨论

Assign 仅将属性从源对象复制到目标对象,如果源值是对象,它会复制引用,因此是浅拷贝。

也许使用 lodash 和 deepClone() 方法。

const clone = _.cloneDeep(original);

【讨论】:

    【解决方案2】:

    正如这里很多人提到的,您需要对象的深层副本。

    V8 中有一个深拷贝方法,目前仅在 NodeJS 中可用,并且可能很快在浏览器中可用,但如果您的脚本在浏览器中运行,您现在无法使用它:

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

    然后在现代浏览器中有一些 hacky 方法可以做到这一点,这种方法不适用于函数,可能有点慢,但可以完成工作,就像这个:

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

    最后还有一些提供深度克隆的库,如果你已经在使用 lodash 或 jquery,那么你很幸运,因为它们附带了这个功能,如果没有,有一个名为 just-clone 的库只提供深度克隆,因此您不必将完整的库添加到您的项目中。

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

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

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

    _.cloneDeep(oldObject);
    

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

    clone(oldObject);
    

    您可能会感兴趣的其他相关问题有很好的答案以获取更多信息:

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

    或者

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 2016-02-21
      • 1970-01-01
      相关资源
      最近更新 更多