在Angular 2 + TypeScript中深度复制数组


71

我有一个对象数组作为输入。让我们称之为吧content

尝试深复制它时,它仍然具有对先前数组的引用。

我需要复制该输入数组,并更改重复部分的一个属性。

很久以来,我尝试了不成功的其他方法。

ES6方式:

public duplicateArray() {
  arr = [...this.content]
  arr.map((x) => {x.status = DEFAULT});
  return this.content.concat(arr);
}

slice方式:

public duplicateArray() {
  arr = this.content.slice(0);
  arr.map((x) => {x.status = DEFAULT});
  return this.content.concat(arr);
}

在这两个对象中,数组中的所有对象都具有status: 'Default'

在Angular 2中深度复制数组的最佳方法是什么?

Answers:


123

检查一下:

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

4
如果我没有丢失某些对字符串不起作用的东西,当我尝试时,var source = ["one","two","three"]; var cloned = source.map(x => Object.assign({},x)); 我最终会克隆为:[ { '0': 'o', '1': 'n', '2': 'e' }, { '0': 't', '1': 'w', '2': 'o' }, { '0': 't', '1': 'h', '2': 'r', '3': 'e', '4': 'e' } ]
ossek

@ ossec,Object.assign()方法将可枚举的属性从源对象复制到目标对象。字符串变量是一个类似数组的对象。每个字符将作为新属性添加到克隆数组中的目标对象。您的示例正确运行,并且在此需要对源数组中的字符串进行其他检查。
YD1m

7
至于我source.map(x => ({ ...x }));最适合。
Frankie Drake


如果要克隆数组对象,则最好使用此选项。
ruchit

47

简单:

let objCopy  = JSON.parse(JSON.stringify(obj));

这也适用(仅适用于阵列)

let objCopy2 = obj.slice()

可能不是最高效,但绝对是最简单的……并且适用于任何对象/数组
Kyle Huang,

3
这可能是一个好主意。但是有一个缺点:我不认为这会复制方法,前提是对象具有方法。
user2367418 '18

我们在生产中使用了此方法,该方法在主模型中具有2个嵌套模型,获取模型的调用工作完美,并且getError()方法也有效
Cameron Gilbert,

比Object.assign([],this.list);保存了我的一天。(行)
roshini

如果对象具有函数属性或循环引用,则将无法使用。
canbax

15

这为我工作:

this.listCopy = Object.assign([], this.list);

@makkasi不是这样。设置this.listCopy之后更改this.list肯定不会影响this.listCopy!
kabus

3
好吧,可能是我错了。我用此代码进行了测试,它更改了其他列表。可能是其他原因造成的。我目前无法使用计算机。稍后再试。我删除了之前的评论。
makkasi

@kabus,它将this.list包含对象。如果您修改中包含的任何对象this.list,则更改将反映到中this.listCopy,因为它仅保留了引用。
el.atomo

@ el.atomo您能提供一个例子,因为我无法复制它
kabus

当然@kabus ,let list = [{a: 1}]; let listCopy = Object.assign([], list); list[0].a = 2; console.log(list[0].a, listCopy[0].a);。抱歉,格式不正确:)
el.atomo

13

我找到的唯一解决方案(在发布问题后几乎立即获得解决方案)是遍历数组并使用 Object.assign()

像这样:

public duplicateArray() {
  let arr = [];
  this.content.forEach((x) => {
    arr.push(Object.assign({}, x));
  })
  arr.map((x) => {x.status = DEFAULT});
  return this.content.concat(arr);
}

我知道这不是最佳选择。我想知道是否有更好的解决方案。



10

深度复制内部具有嵌套对象的对象的一种干净方法是使用lodash的cloneDeep方法。

对于Angular,您可以这样操作:

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

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

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

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

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


1
请注意,如果您的originalObject是对象数组,则不会深度复制对象,它们的引用将被复制。
Slaven Tomac


1

这是我自己的。在复杂的情况下不起作用,但是对于简单的对象数组,这已经足够了。

  deepClone(oldArray: Object[]) {
    let newArray: any = [];
    oldArray.forEach((item) => {
      newArray.push(Object.assign({}, item));
    });
    return newArray;
  }

0

另外,您可以使用GitHub项目ts-deepcopy(也可在npm上获得)来克隆您的对象,或仅在下面添加代码段。

/**
 * Deep copy function for TypeScript.
 * @param T Generic type of target/copied value.
 * @param target Target value to be copied.
 * @see Source project, ts-deepcopy https://github.com/ykdr2017/ts-deepcopy
 * @see Code pen https://codepen.io/erikvullings/pen/ejyBYg
 */
export const deepCopy = <T>(target: T): T => {
  if (target === null) {
    return target;
  }
  if (target instanceof Date) {
    return new Date(target.getTime()) as any;
  }
  if (target instanceof Array) {
    const cp = [] as any[];
    (target as any[]).forEach((v) => { cp.push(v); });
    return cp.map((n: any) => deepCopy<any>(n)) as any;
  }
  if (typeof target === 'object' && target !== {}) {
    const cp = { ...(target as { [key: string]: any }) } as { [key: string]: any };
    Object.keys(cp).forEach(k => {
      cp[k] = deepCopy<any>(cp[k]);
    });
    return cp as T;
  }
  return target;
};

0

我在angular devkit中发现了深复制方法,这很正常,所以...也许您可以自己实现或使用它。

我更喜欢使用loadash,可以使用很多对象和数组操作方法。

import { deepCopy } from '@angular-devkit/core/src/utils/object';

export class AppComponent {
  source = {
    ....
  }
  constructor() {
     const newObject = deepCopy(this.source);
  }
}
Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1000.8
@angular-devkit/build-angular     0.1000.8
@angular-devkit/build-optimizer   0.1000.8
@angular-devkit/build-webpack     0.1000.8
@angular-devkit/core              10.0.8
@angular-devkit/schematics        10.0.8
@angular/cli                      10.0.8
@ngtools/webpack                  10.0.8
@schematics/angular               10.0.8
@schematics/update                0.1000.8
rxjs                              6.5.5
typescript                        3.9.7
webpack                           4.43.0

-1

您可以使用use JQuery进行深度复制:

var arr =[['abc'],['xyz']];
var newArr = $.extend(true, [], arr);
newArr.shift().shift();

console.log(arr); //arr still has [['abc'],['xyz']]
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.