Copia profunda de una matriz en Angular 2 + TypeScript


Tengo una matriz de objetos que es una entrada. Vamos a llamarlo content.

Al intentar copiarlo en profundidad, todavía tiene una referencia a la matriz anterior.

Necesito duplicar esa matriz de entrada y cambiar una propiedad de la parte duplicada.

Tanto tiempo he intentado diferentes métodos que no tuvieron éxito.

ES6 camino:

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

El camino slice:

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

En ambos, todos los objetos dentro del array tienen status: 'Default'.

¿Cuál es el mejor enfoque para copiar profundamente la matriz en Angular 2?

Author: Joel Almeida, 2016-02-19

11 answers

Comprueba esto:

  let cloned = source.map(x => Object.assign({}, x));
 67
Author: YD1m,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-30 13:32:16

Simple:

let objCopy  = JSON.parse(JSON.stringify(obj));
 20
Author: Cameron Gilbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-21 03:01:40

Esto está funcionando para mí:

this.listCopy = Object.assign([], this.list);
 14
Author: kabus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-14 13:56:53

La única solución que he encontrado (casi instantáneamente después de publicar la pregunta), es recorrer el array y usar Object.assign()

Así:

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

Sé que esto no es óptimo. Y me pregunto si hay alguna solución mejor.

 13
Author: Joel Almeida,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-19 11:35:06

Una forma limpia de copiar en profundidad objetos que tienen objetos anidados dentro es usando el método cloneDeep de lodash.

Para Angular, puedes hacerlo así:

Instala lodash con yarn add lodash o npm install lodash.

En tu componente, importa cloneDeep y úsalo:

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

Solo son 18kb añadidos a tu compilación, bien vale la pena por los beneficios.

También he escrito un artículo aquí, si necesita más información sobre por qué usar cloneDeep de lodash.

 5
Author: BogdanC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-15 15:59:36

Aquí está la mía. No funciona para casos complejos, pero para una simple matriz de Objetos, es lo suficientemente bueno.

  deepClone(oldArray: Object[]) {
    let newArray: any = [];
    oldArray.forEach((item) => {
      newArray.push(Object.assign({}, item));
    });
    return newArray;
  }
 1
Author: Alex Beugnet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-13 15:10:32

Puede usar usar jQuery para copiar profundamente:

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

console.log(arr); //arr still has [['abc'],['xyz']]
 0
Author: Riya Goel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-20 06:39:03

Me gustaría cloneDeep método de Lodash para esto.

 0
Author: Hung Bui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-13 08:22:09
let originalArray :string[]  = ['one', 'two', 'Sc-fi'];
let cloneArray :string[]  = originalArray.concat([]);
 0
Author: Adam111p,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-28 20:52:23

Alternativamente, puede usar el proyecto GitHub ts-deepcopy, que también está disponible en npm, para clonar su objeto, o simplemente incluir el fragmento de código a continuación.

/**
 * 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
Author: Erik Vullings,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-30 10:53:00

Esta es la sugerencia de Daria (ver comentario sobre la pregunta) que funciona a partir de TypeScript 2.1 y básicamente clona cada elemento del array :

this.clonedArray = theArray.map(e => ({ ... e }));
 0
Author: Alexei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 14:02:04