在Angular中深度复制对象


70

AngularJS必须angular.copy()深度复制对象和数组。

Angular是否也有类似的东西?



Duplicate也许,但是我想要一个non-polyfill解决方案。就像angular.copy()
Ankit Singh

这就是我们所拥有的。
君特Zöchbauer

所以,没有angular.copy()。我应该删除问题吗?
Ankit Singh

大概吧。似乎并没有提供太多价值,因为还有一个非常相似的问题。
君特Zöchbauer

Answers:


85

您还可以使用:

JSON.parse(JSON.stringify(Object))

如果在您的范围内,则在每个Angular组件,指令等中,并且在每个节点环境中。

除非您有循环引用,否则它应该起作用并将有效地将变量引用与原始对象分离。


1
这似乎是一个非常简单有效的深层副本!为什么得分不高?这个答案有问题吗?
TSG

对于将删除所有引用的深度复制解决方案,这是最好的方法,可在Browser / CommonJS等设备上使用。在需要对象快照的生产环境中,我将其用于生产中。我想我来得晚了一点,比如迟了一年。@TSG
Gabriel

2
另外,如果您使用带有函数(不只是值)的对象文字,它们将被忽略,但是您可以轻松地合并Object.assing({}, oldObject, JSON.parse(JSON.stringify(oldObject))),这将从对象文字中重新填充函数属性,并且使用JSON将创建深层副本而无需与原著有任何关系。
加百利·巴尔萨·坎图

我认为最好的答案
Johannes Wanzek '18

3
但是要注意,当有一些日期时,这是行不通的。
弗朗Žiačik

22

这个问题不是我如何在angular 2中使用angular.copy的重复,因为OP正在询问深复制对象。链接的答案推荐不进行深层复制的Object.assign()

其实用Angular2不使用其他库,例如限制你的jQuery深拷贝与他们的对象$ .clone()函数或lodash_.cloneDeep()

最常见的库可通过键入CLI工具提供其键入,因此即使从TypeScript进行编译,您也可以无缝使用所需的任何内容。

另请参阅:在JavaScript中深度克隆对象的最有效方法是什么?


当目标对象中存在嵌套对象时,Object.assign()不会进行深度复制,因此,作为一个幼稚的解决方案,您可以遍历目标对象并对每个对象的属性进行Object.assign()!它的工作对我来说,当我不想对任何第三方库的依赖性
达尼韦韦

21

另一种选择是实现自己的功能:

/**
 * Returns a deep copy of the object
 */
public static deepCopy(oldObj: any) {
    var newObj = oldObj;
    if (oldObj && typeof oldObj === "object") {
        if (oldObj instanceof Date) {
           return new Date(oldObj.getTime());
        }
        newObj = Object.prototype.toString.call(oldObj) === "[object Array]" ? [] : {};
        for (var i in oldObj) {
            newObj[i] = this.deepCopy(oldObj[i]);
        }
    }
    return newObj;
}

1
我无法使用这种方法来深度复制日期
A_J


11

您可以deep copy使用lodash的cloneDeep方法在Angular中使用对象:

使用yarn add lodash或安装lodash npm install lodash

在您的组件中,导入cloneDeep并使用它:

import * as cloneDeep from 'lodash/cloneDeep';
...
clonedObject = cloneDeep(originalObject);

它仅增加了18kb,值得物有所值。

如果您需要更多关于为何使用lodash的cloneDeep的见解,我也在这里写了一篇文章


使用Lodash按值复制对我不起作用。你也许知道为什么吗?我仍在获取参考值,因此,如果我更改一个,它们都将同时更改。
弗拉基米尔·德斯波托维奇

5
Create helper class with name deepCopy.ts

/*
* DeepCopy class helps to copy an Original Array or an Object without impacting on original data
*/

export class DeepCopy {

  static copy(data: any) {
    let node;
    if (Array.isArray(data)) {
      node = data.length > 0 ? data.slice(0) : [];
      node.forEach((e, i) => {
        if (
          (typeof e === 'object' && e !== {}) ||
          (Array.isArray(e) && e.length > 0)
        ) {
          node[i] = DeepCopy.copy(e);
        }
      });
    } else if (data && typeof data === 'object') {
      node = data instanceof Date ? data : Object.assign({}, data);
      Object.keys(node).forEach((key) => {
        if (
          (typeof node[key] === 'object' && node[key] !== {}) ||
          (Array.isArray(node[key]) && node[key].length > 0)
        ) {
          node[key] = DeepCopy.copy(node[key]);
        }
      });
    } else {
      node = data;
    }
    return node;
  }
}

根据需要导入deepCopy文件,并使用以下代码 DeepCopy.copy(arg); ,这里arg将是您想要的对象或数组


这实际上是最好的答案。它可以有效地深度复制数据,而无需导入外部库。我不想引入整个库仅使用一个函数(即使只有18KB)。
–Frozenfrank19

1

如果源是对象数组,请使用map:

let cloned = source.map(x => Object.assign({}, x));

要么

let cloned = source.map((x) => {
                return { ...x };
             });

1

KrishnamrajuK答案的一些修改

export class DeepCopy {
  static copy(data: any, objMap?: WeakMap<any, any>) {
    if (!objMap) {
      // Map for handle recursive objects
      objMap = new WeakMap();
    }

    // recursion wrapper
    const deeper = value => {
      if (value && typeof value === 'object') {
        return DeepCopy.copy(value, objMap);
      }
      return value;
    };

    // Array value
    if (Array.isArray(data)) return data.map(deeper);

    // Object value
    if (data && typeof data === 'object') {
      // Same object seen earlier
      if (objMap.has(data)) return objMap.get(data);
      // Date object
      if (data instanceof Date) {
        const result = new Date(data.valueOf());
        objMap.set(data, result);
        return result;
      }
      // Use original prototype
      const node = Object.create(Object.getPrototypeOf(data));
      // Save object to map before recursion
      objMap.set(data, node);
      for (const [key, value] of Object.entries(data)) {
        node[key] = deeper(value);
      }
      return node;
    }
    // Scalar value
    return data;
  }
}


0

我面临着深复制的问题。angular.copy({},factory)和angular.extend({},factory)对于数组对象或哈希对象很有帮助,但是在复制对象时,有时会存在连接依赖项问题。我解决了这个问题,所以:

 copyFactory = (() ->
    resource = ->
      resource.__super__.constructor.apply this, arguments
      return
    this.extendTo resource
    resource
  ).call(factory)

-1

我在Typescript中创建了一个非常简单的函数,该函数接受所有可能的输入并提供该对象的深层克隆副本。

希望它能帮助到别人。

  public deepCopy(obj) {

    var clonedObject: any;

    if (obj instanceof Array) {
        var itemArray = Object.assign([], obj);
        clonedObject = itemArray;

        for (var j = 0; j < clonedObject.length; j++) {
            clonedObject[j] = this.deepCopy(clonedObject[j]);
        }

        return clonedObject;
    }
    else if (typeof obj === 'number' || typeof obj == 'string') {
        return obj
    }
    else {


        var item = Object.assign({}, obj);
        clonedObject = item;

        let allKeys = Object.keys(clonedObject);

        for (var i = 0; i < allKeys.length; i++) {
            if (clonedObject[allKeys[i]] instanceof Array) {
                //If the calue is Array
                clonedObject[allKeys[i]] = this.deepCopy(clonedObject[allKeys[i]]);
            }
            else if (clonedObject[allKeys[i]] instanceof Date) {
                clonedObject[allKeys[i]] = new Date(clonedObject[allKeys[i]].valueOf());
            }
            else if (clonedObject[allKeys[i]] instanceof Object){
                //if the value is JOBJECT.
                clonedObject[allKeys[i]] = this.deepCopy(clonedObject[allKeys[i]]);
            }
        }
        return clonedObject;
    }


}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.