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

Posted

技术标签:

【中文标题】在 Angular 2 + TypeScript 中深度复制数组【英文标题】:Deep copy an array in Angular 2 + TypeScript 【发布时间】:2016-05-31 23:13:09 【问题描述】:

我有一个作为输入的对象数组。让我们称之为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 中深度复制数组的最佳方法是什么?

【问题讨论】:

【参考方案1】:

检查一下:

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

【讨论】:

如果我没有遗漏一些这对字符串不起作用的东西——当我尝试 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' ] 对我来说source.map(x => ( ...x )); 最合适。 不兼容 Internet Explorer developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 如果要克隆数组对象,这个选项更可取。 经过 2 小时的搜索。这行得通!非常感谢!【参考方案2】:

简单:

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

这也有效(仅适用于数组)

let objCopy2 = obj.slice()

【讨论】:

可能不是最有效的,但绝对是最简单的......并且适用于任何对象/数组 这可能是个好主意。但是有一个但是:我不认为这会复制方法,假设对象有方法。 比 Object.assign([], this.list); (行) 如果对象有函数属性或循环引用,这将不起作用。 JSON.stringify 有一个替换函数JSON.stringify(<object>, <replacer func>) 用于处理循环和函数属性【参考方案3】:

这对我有用:

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

【讨论】:

@makkasi 这不是真的。设置 this.listCopy 后更改 this.list,肯定不会影响 this.listCopy! 好的。可能是我错了。我用这段代码进行了测试,它改变了另一个列表。可能是其他地方的原因。我暂时无法使用电脑。稍后会尝试这个。我删除了我之前的评论。 @kabus,如果this.list 包含对象,它将。如果您修改 this.list 中包含的任何对象,更改将反映到 this.listCopy,因为它只保留引用。 @el.atomo 你能提供一个例子吗,因为我无法复制它 当然@kabus,let list = [a: 1]; let listCopy = Object.assign([], list); list[0].a = 2; console.log(list[0].a, listCopy[0].a);。对不起,丑陋的格式:)【参考方案4】:

我找到的唯一解决方案(几乎在发布问题后立即)是循环遍历数组并使用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);

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

【讨论】:

不兼容 Internet Explorer developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案5】:

这是Daria 的建议(见问题评论),从TypeScript 2.1 开始,基本上是clones each element from the array:

this.clonedArray = theArray.map(e => ( ... e ));

【讨论】:

这对我有用!谢谢阿列克谢!!非常简单优雅:) 看起来也很快,不需要包含额外的 lodash 库。 我发现这是真正进行深度克隆的唯一方法。 JSON.parse(JSON.stringify(obj)) 有效,但将整数值转换为字符串。【参考方案6】:

使用 lodash 的 cloneDeep 方法来深度复制具有嵌套对象的对象的一种简洁方法。

对于 Angular,您可以这样做:

使用yarn add lodashnpm install lodash 安装lodash。

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

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

它只增加了 18kb 到您的构建中,非常值得。

我还写了一个article here,如果您需要更深入地了解为什么要使用 lodash 的 cloneDeep。

【讨论】:

请注意,如果您的 originalObject 是对象数组,则对象不会被深度复制,它们的引用将被复制。【参考方案7】:

我在 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

【讨论】:

真棒解决方案,竖起大拇指【参考方案8】:

这是我自己的。不适用于复杂的情况,但对于简单的 Objects 数组,就足够了。

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

【讨论】:

【参考方案9】:

或者,您可以使用 GitHub 项目 ts-deepcopy(也可以在 npm 上获得)来克隆您的对象,或者只包含下面的代码 sn-p。

/**
 * 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;
;

【讨论】:

【参考方案10】:

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

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

console.log(arr); //arr still has [['abc'],['xyz']]

【讨论】:

以上是关于在 Angular 2 + TypeScript 中深度复制数组的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 2 / Typescript 中使用 IScroll

如何在 Angular 2 的 TypeScript 中映射嵌套的 Json

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

使用 Typescript 在 Angular 2 中的组件之间共享行为

带有 TypeScript 的 Angular 2 [关闭]

Angular 2 中的 const 和 Typescript