在 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 lodash
或npm 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 中的组件之间共享行为