在typescript中创建一个数组的克隆

Aru*_*run 49 arrays typescript angular

我有两个对象的数组:

genericItems: Item[] = [];
backupData: Item[] = [];
Run Code Online (Sandbox Code Playgroud)

我用genericItems数据填充我的html表.该表是可修改的.有一个重置按钮可以撤消所有已完成的更改backUpData.此数组由服务填充:

getGenericItems(selected: Item) {
this.itemService.getGenericItems(selected).subscribe(
  result => {
     this.genericItems = result;
  });
     this.backupData = this.genericItems.slice();
  }
Run Code Online (Sandbox Code Playgroud)

我的想法是,用户更改将反映在第一个阵列中,第二个阵列可用作重置操作的备份.我在这里面临的问题是当用户修改表(genericItems [])时,第二个数组genericItems[])也会被修改.这是怎么回事以及如何防止这种情况发生的?

aba*_*het 102

试试这个 :

克隆数组:

const myClonedArray  = Object.assign([], myArray);
Run Code Online (Sandbox Code Playgroud)

克隆一个对象:

const myClonedObject = Object.assign({}, myObject);
Run Code Online (Sandbox Code Playgroud)

  • 如果你的数组是一个对象数组(不是原始类型),那么你需要使用浅层副本更深层次.对我来说,解决方案是迭代数组并克隆对象.即`const myArray = [{a:'a',b:'b'},{a:'c',b:'d'}]​​; const myClonedArray = []; myArray.map(val => myClonedArray.push(Object.assign({},val)));`.正确深度复制的替代解决方案是用于其他答案中提到的JSON序列化. (11认同)
  • @mumblesNZ,如果你真的在谈论深层副本,那么两个级别也不够。你必须使用 Lodash 的 `_.cloneDeep(obj)` 之类的东西。正如您所说,JSON 序列化可以工作,但这是一种非常迂回的方法。 (3认同)

Dav*_*han 31

Typescript和ES6中,您可以使用spread运算符:

const myClonedArray  = [...myArray];  // This is ok for [1,2,'test','bla']
                                      // But wont work for [{a:1}, {b:2}]. 
                                      // A bug will occur when you 
                                      // modify the clone and you expect the 
                                      // original not to be modified.
                                      // The solution is to do a deep copy
                                      // when you are cloning an array of objects.
Run Code Online (Sandbox Code Playgroud)

spread操作符也适用于对象,但它只会执行浅层复制(第一层子项)

import * as cloneDeep from 'lodash/cloneDeep';
const myClonedArray = cloneDeep(myArray);     // This works for [{a:1}, {b:2}]
Run Code Online (Sandbox Code Playgroud)

要执行对象的深层复制,您需要一个外部库:

const myShallowClonedObject = {...myObject};   // Will do a shallow copy
                                               // and cause you an un expected bug.
Run Code Online (Sandbox Code Playgroud)

  • 啊! 一分钱掉下来!是时候停止使用扩展运算符来克隆对象数组了 (3认同)
  • 不,不是的。尝试修改您的克隆项目,它也会修改原始项目。你所拥有的是通过引用复制而不是价值。 (3认同)
  • 对于深度克隆也可以使用“Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);” 而不是使用外部库。 (2认同)

Gau*_*war 10

试试下面的代码:

this.cloneArray= [...this.OriginalArray]
Run Code Online (Sandbox Code Playgroud)


jmu*_*ire 9

使用地图或其他类似解决方案无助于深深克隆对象数组。在不添加新库的情况下执行此操作的更简单方法是使用JSON.stringfy,然后使用JSON.parse。

在你的情况下,这应该工作:

this.backupData = JSON.parse(JSON.stringify(genericItems));
Run Code Online (Sandbox Code Playgroud)


Nir*_*rus 6

数组复制解释 - Deep & Shallow

下面的代码可能会帮助您复制第一级对象

let original = [{ a: 1 }, {b:1}]
const copy = [ ...original ].map(item=>({...item}))
Run Code Online (Sandbox Code Playgroud)

所以对于下面的情况,值保持不变

copy[0].a = 23
console.log(original[0].a) //logs 1 -- value didn't change voila :)
Run Code Online (Sandbox Code Playgroud)

对于这种情况失败

let original = [{ a: {b:2} }, {b:1}]
const copy = [ ...original ].map(item=>({...item}))
copy[0].a.b = 23;
console.log(original[0].a) //logs {b: 23} -- lost the original one :(
Run Code Online (Sandbox Code Playgroud)

尝试 lodash 单独的 ES 模块 -cloneDeep:

我想说的是 lodash cloneDeepAPI(它可以作为一个单独的模块安装,减少了 treeshaking 的代码占用),它可以帮助您复制对象内的对象,完全与原始对象解除引用。作为另一种选择,您也可以依靠JSON.stringify&JSON.parse 方法来快速且高性能地取消引用。

请参阅文档: https: //github.com/lodash/lodash

单独包https://www.npmjs.com/package/lodash.clonedeep


Ami*_*agh 6

你可以使用地图功能

 toArray= fromArray.map(x => x);
Run Code Online (Sandbox Code Playgroud)


Fra*_*ica 5

代码中的以下行创建一个新数组,将所有对象引用复制genericItems到该新数组中,并将其分配给backupData

this.backupData = this.genericItems.slice();
Run Code Online (Sandbox Code Playgroud)

因此,虽然backupDatagenericItems是不同的数组,但它们包含完全相同的对象引用。

您可以引入一个库为您进行深度复制(如@LatinWarrior 所述)。

但是如果Item不是太复杂,也许你可以clone给它添加一个方法来自己深度克隆对象:

class Item {
  somePrimitiveType: string;
  someRefType: any = { someProperty: 0 };

  clone(): Item {
    let clone = new Item();

    // Assignment will copy primitive types

    clone.somePrimitiveType = this.somePrimitiveType;

    // Explicitly deep copy the reference types

    clone.someRefType = {
      someProperty: this.someRefType.someProperty
    };

    return clone;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后调用clone()每个项目:

this.backupData = this.genericItems.map(item => item.clone());
Run Code Online (Sandbox Code Playgroud)


Was*_*siF 5

以非常强大的方式克隆对象/数组(没有引用)

您可以使用object/来获取/ 的深层复制。array@angular-devkit

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

export class AppComponent {

  object = { .. some object data .. }
  array = [ .. some list data .. ]

  constructor() {
     const newObject = deepCopy(this.object);
     const newArray = deepCopy(this.array);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 太棒了,这很有效,对于不喜欢或不依赖“loaddash”的人来说,这是一个本机解决方案 (2认同)