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

时间:2017-06-28 17:17:06

标签: arrays angular typescript

我有两个对象的数组:

genericItems: Item[] = [];
backupData: Item[] = [];

我使用genericItems数据填充我的html表格。该表是可修改的。有一个重置按钮可以撤消对backUpData所做的所有更改。该数组由服务填充:

getGenericItems(selected: Item) {
this.itemService.getGenericItems(selected).subscribe(
  result => {
     this.genericItems = result;
  });
     this.backupData = this.genericItems.slice();
  }

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

15 个答案:

答案 0 :(得分:67)

试试这个:

克隆数组:

const myClonedArray  = Object.assign([], myArray);

克隆对象:

const myClonedObject = Object.assign({}, myObject);

答案 1 :(得分:14)

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

const myClonedArray  = [...myArray];

spread运算符也适用于对象,但只会做浅表复制(第一层子级)

const myShallowClonedObject = {...myObject};

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

 import * as cloneDeep from 'lodash/cloneDeep';
 const deeplyClonedObject = cloneDeep(myObject);

答案 2 :(得分:8)

尝试以下代码:

this.cloneArray= [...this.OriginalArray]

答案 3 :(得分:2)

使用地图或其他类似解决方案无助于深深克隆对象数组。 无需添加新库即可轻松实现此目的的方法是先使用JSON.stringfy,然后使用JSON.parse。

在这种情况下,这应该可以工作:

this.backupData = JSON.parse(JSON.stringify( genericItems));

答案 4 :(得分:1)

试试这个:

[https://lodash.com/docs/4.17.4#clone][1]

var objects = [{ 'a': 1 }, { 'b': 2 }];

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

答案 5 :(得分:1)

我和primeNg DataTable有同样的问题。在尝试和哭泣之后,我已经使用此代码解决了问题。

private deepArrayCopy(arr: SelectItem[]): SelectItem[] {
    const result: SelectItem[] = [];
    if (!arr) {
      return result;
    }
    const arrayLength = arr.length;
    for (let i = 0; i <= arrayLength; i++) {
      const item = arr[i];
      if (item) {
        result.push({ label: item.label, value: item.value });
      }
    }
    return result;
  }

用于初始化备份值

backupData = this.deepArrayCopy(genericItems);

重置更改

genericItems = this.deepArrayCopy(backupData);

灵丹妙药是使用{}而不是调用构造函数来重新创建项目。 我已经尝试了new SelectItem(item.label, item.value)无法正常工作。

答案 6 :(得分:1)

克隆数组的最简单方法是 backUpData = genericItems.concat();

这将为数组索引创建一个新内存

答案 7 :(得分:0)

看起来你可能犯了一个关于你在做数组副本的错误。看看下面我的解释和对代码的一些修改,它可以帮助您将数据重置为以前的状态。

在您的示例中,我可以看到以下内容:

  • 您正在请求获取通用项目
  • 获取数据后,将结果设置为this.genericItems
  • 之后直接将backupData设置为结果

我是否正确地认为你不希望第3点按顺序发生?

会更好吗

  • 您执行数据请求
  • 制作this.genericItems
  • 中当前内容的备份副本
  • 然后将genericItems设置为您的请求的结果

试试这个:

getGenericItems(selected: Item) {
  this.itemService.getGenericItems(selected).subscribe(
    result => {
       // make a backup before you change the genericItems
       this.backupData = this.genericItems.slice();

       // now update genericItems with the results from your request
       this.genericItems = result;
    });
  }

答案 8 :(得分:0)

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

this.backupData = this.genericItems.slice();

因此,虽然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;
  }
}

然后在每个项目上调用clone()

this.backupData = this.genericItems.map(item => item.clone());

答案 9 :(得分:0)

看起来你想要的是对象的深层复制。为什么不使用Object.assign()?不需要图书馆,它是一个单行代码:)

getGenericItems(selected: Item) {
    this.itemService.getGenericItems(selected).subscribe(
        result => {
            this.genericItems = result;
            this.backupDate = Object.assign({}, result); 
            //this.backupdate WILL NOT share the same memory locations as this.genericItems
            //modifying this.genericItems WILL NOT modify this.backupdate
        });
}

有关Object.assign()的更多信息:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

答案 10 :(得分:0)

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

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

因此对于以下情况,值保持不变

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

此案件失败

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

最终建议:

我想说的是lodash cloneDeep API,它可以帮助您复制完全取消引用原始对象的对象内的对象。这可以作为单独的模块安装。

参考文档: https://github.com/lodash/lodash

个别套餐https://www.npmjs.com/package/lodash.clonedeep

答案 11 :(得分:0)

您可以使用地图功能

 toArray= fromArray.map(x => x);

答案 12 :(得分:0)

如果数组中的项目不是原始项目,则可以使用传播运算符来实现。

this.plansCopy = this.plans.map(obj => ({...obj}));

完整答案:https://stackoverflow.com/a/47776875/5775048

答案 13 :(得分:0)

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

您可以使用 object 获取 array / @angular-devkit 的深层副本。

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

export class AppComponent {

  object = { .... }
  array = [ ... ]

  constructor() {
     const newObject = deepCopy(this.object);
     const newArray = deepCopy(this.array);
  }
}

答案 14 :(得分:-1)

尝试一下

$.extend(true, [], originalArray)在数组的情况下,特别是在由对象组成的情况下

$.extend(true, {}, originalObject)(如果有对象)