angular

¿Qué es alternativa a angular.copy en Angular?



clone object angular 6 (13)

¿Cómo puedo copiar un objeto y perder su referencia en Angular?

Con AngularJS, puedo usar angular.copy(object) , pero angular.copy(object) algún error al usar eso en Angular.

EXCEPCIÓN: ReferenceError: angular no está definido


Como otros ya han señalado, usar lodash o subrayado es probablemente la mejor solución. Pero si no necesita esas bibliotecas para otra cosa, probablemente pueda usar algo como esto:

function deepClone(obj) { // return value is input is not an Object or Array. if (typeof(obj) !== ''object'' || obj === null) { return obj; } let clone; if(Array.isArray(obj)) { clone = obj.slice(); // unlink Array reference. } else { clone = Object.assign({}, obj); // Unlink Object reference. } let keys = Object.keys(clone); for (let i=0; i<keys.length; i++) { clone[keys[i]] = deepClone(clone[keys[i]]); // recursively unlink reference to nested objects. } return clone; // return unlinked clone. }

Eso es lo que decidimos hacer.


Hasta que tengamos una mejor solución, puede usar lo siguiente:

duplicateObject = <YourObjType> JSON.parse(JSON.stringify(originalObject));

EDITAR: Aclaración

Tenga en cuenta: la solución anterior solo pretendía ser una solución rápida, proporcionada en un momento en que Angular 2 estaba en desarrollo activo. Mi esperanza era que eventualmente pudiéramos obtener un equivalente de angular.copy() . Por lo tanto, no quería escribir o importar una biblioteca de clonación profunda.

Este método también tiene problemas con las propiedades de la fecha de análisis (se convertirá en una cadena).

No utilice este método en aplicaciones de producción . Úselo solo en sus proyectos experimentales, los que está haciendo para aprender Angular 2.


He creado un servicio para usar con Angular 5 o superior, usa la base angular.copy () de angularjs, funciona bien para mí. Además, hay otras funciones como isUndefined , etc. Espero que ayude. Como cualquier optimización, sería bueno saberlo. Saludos

import { Injectable } from ''@angular/core''; @Injectable({providedIn: ''root''}) export class AngularService { private TYPED_ARRAY_REGEXP = /^/[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array/]$/; private stackSource = []; private stackDest = []; constructor() { } public isNumber(value: any): boolean { if ( typeof value === ''number'' ) { return true; } else { return false; } } public isTypedArray(value: any) { return value && this.isNumber(value.length) && this.TYPED_ARRAY_REGEXP.test(toString.call(value)); } public isArrayBuffer(obj: any) { return toString.call(obj) === ''[object ArrayBuffer]''; } public isUndefined(value: any) {return typeof value === ''undefined''; } public isObject(value: any) { return value !== null && typeof value === ''object''; } public isBlankObject(value: any) { return value !== null && typeof value === ''object'' && !Object.getPrototypeOf(value); } public isFunction(value: any) { return typeof value === ''function''; } public setHashKey(obj: any, h: any) { if (h) { obj.$$hashKey = h; } else { delete obj.$$hashKey; } } private isWindow(obj: any) { return obj && obj.window === obj; } private isScope(obj: any) { return obj && obj.$evalAsync && obj.$watch; } private copyRecurse(source: any, destination: any) { const h = destination.$$hashKey; if (Array.isArray(source)) { for (let i = 0, ii = source.length; i < ii; i++) { destination.push(this.copyElement(source[i])); } } else if (this.isBlankObject(source)) { for (const key of Object.keys(source)) { destination[key] = this.copyElement(source[key]); } } else if (source && typeof source.hasOwnProperty === ''function'') { for (const key of Object.keys(source)) { destination[key] = this.copyElement(source[key]); } } else { for (const key of Object.keys(source)) { destination[key] = this.copyElement(source[key]); } } this.setHashKey(destination, h); return destination; } private copyElement(source: any) { if (!this.isObject(source)) { return source; } const index = this.stackSource.indexOf(source); if (index !== -1) { return this.stackDest[index]; } if (this.isWindow(source) || this.isScope(source)) { throw console.log(''Cant copy! Making copies of Window or Scope instances is not supported.''); } let needsRecurse = false; let destination = this.copyType(source); if (destination === undefined) { destination = Array.isArray(source) ? [] : Object.create(Object.getPrototypeOf(source)); needsRecurse = true; } this.stackSource.push(source); this.stackDest.push(destination); return needsRecurse ? this.copyRecurse(source, destination) : destination; } private copyType = (source: any) => { switch (toString.call(source)) { case ''[object Int8Array]'': case ''[object Int16Array]'': case ''[object Int32Array]'': case ''[object Float32Array]'': case ''[object Float64Array]'': case ''[object Uint8Array]'': case ''[object Uint8ClampedArray]'': case ''[object Uint16Array]'': case ''[object Uint32Array]'': return new source.constructor(this.copyElement(source.buffer), source.byteOffset, source.length); case ''[object ArrayBuffer]'': if (!source.slice) { const copied = new ArrayBuffer(source.byteLength); new Uint8Array(copied).set(new Uint8Array(source)); return copied; } return source.slice(0); case ''[object Boolean]'': case ''[object Number]'': case ''[object String]'': case ''[object Date]'': return new source.constructor(source.valueOf()); case ''[object RegExp]'': const re = new RegExp(source.source, source.toString().match(/[^//]*$/)[0]); re.lastIndex = source.lastIndex; return re; case ''[object Blob]'': return new source.constructor([source], {type: source.type}); } if (this.isFunction(source.cloneNode)) { return source.cloneNode(true); } } public copy(source: any, destination?: any) { if (destination) { if (this.isTypedArray(destination) || this.isArrayBuffer(destination)) { throw console.log(''Cant copy! TypedArray destination cannot be mutated.''); } if (source === destination) { throw console.log(''Cant copy! Source and destination are identical.''); } if (Array.isArray(destination)) { destination.length = 0; } else { destination.forEach((value: any, key: any) => { if (key !== ''$$hashKey'') { delete destination[key]; } }); } this.stackSource.push(source); this.stackDest.push(destination); return this.copyRecurse(source, destination); } return this.copyElement(source); } }


La alternativa para copiar objetos profundos que tienen objetos anidados en el interior es mediante el uso del método cloneDeep de lodash.

Para Angular, puede hacerlo así:

Instale lodash con yarn add lodash o npm install lodash .

En su componente, importe cloneDeep y cloneDeep :

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

Solo se agregan 18kb a su construcción, vale la pena por los beneficios.

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


La solución más simple que he encontrado es:

let yourDeepCopiedObject = _.cloneDeep(yourOriginalObject);

* PASOS IMPORTANTES: Debe instalar lodash para usar esto (que no estaba claro en otras respuestas):

$ npm install --save lodash $ npm install --save @types/lodash

y luego impórtalo en tu archivo ts:

import * as _ from "lodash";


Necesitaba esta función solo para formar los ''modelos'' de mi aplicación (datos de fondo sin procesar convertidos en objetos). Así que terminé usando una combinación de Object.create (crear un nuevo objeto a partir del prototipo especificado) y Object.assign (copiar propiedades entre objetos). Necesita manejar la copia profunda manualmente. Creé una esencia para esto.


Para una copia superficial , puede usar Object.assign, que es una función de ES6

let x = { name: ''Marek'', age: 20 }; let y = Object.assign({}, x); x === y; //false

NO lo use para clonación profunda


Si desea copiar una instancia de clase, también puede usar Object.assign, pero debe pasar una nueva instancia como primer parámetro (en lugar de {}):

class MyClass { public prop1: number; public prop2: number; public summonUnicorn(): void { alert(''Unicorn !''); } } let instance = new MyClass(); instance.prop1 = 12; instance.prop2 = 42; let wrongCopy = Object.assign({}, instance); console.log(wrongCopy.prop1); // 12 console.log(wrongCopy.prop2); // 42 wrongCopy.summonUnicorn() // ERROR : undefined is not a function let goodCopy = Object.assign(new MyClass(), instance); console.log(goodCopy.prop1); // 12 console.log(goodCopy.prop2); // 42 goodCopy.summonUnicorn() // It works !


Suponiendo que está utilizando ES6, puede usar var copy = Object.assign({}, original) . Funciona en navegadores modernos; si necesita admitir navegadores antiguos, consulte este polyfill

actualizar:

Con TypeScript 2.1+, la notación abreviada de objetos ES6 está disponible:

const copy = { ...original }


Tuve el mismo problema y no quería usar ningún complemento solo para una clonación profunda:

static deepClone(object): any { const cloneObj = (<any>object.constructor()); const attributes = Object.keys(object); for (const attribute of attributes) { const property = object[attribute]; if (typeof property === ''object'') { cloneObj[attribute] = this.deepClone(property); } else { cloneObj[attribute] = property; } } return cloneObj; }

Créditos: hice esta función más legible , verifique las excepciones a su funcionalidad a continuación


Use lodash como se indica bertandg. La razón por la que angular ya no tiene este método es porque angular 1 era un marco independiente, y las bibliotecas externas a menudo tenían problemas con el contexto de ejecución angular. Angular 2 no tiene ese problema, así que usa la biblioteca que desees.

lodash.com/docs#cloneDeep


Yo y usted enfrentamos un problema de trabajo angular.copy y angular.expect porque no copian el objeto ni crean el objeto sin agregar algunas dependencias. Mi solución fue esta:

copyFactory = (() -> resource = -> resource.__super__.constructor.apply this, arguments return this.extendTo resource resource ).call(factory)


let newObj = JSON.parse(JSON.stringify(obj))

El método JSON.stringify() convierte un objeto o valor de JavaScript en una cadena JSON