En muchas situaciones, es posible que desee utilizar, .copy()pero en realidad no lo necesitaría. En varios proyectos de AngJS1 que he visto, fue una exageración, donde una copia manual de las subestructuras relevantes habría hecho un código más limpio. Tal vez eso fue parte de la decisión de no implementarlo por el equipo de Angular.
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:
Tenga en cuenta que angular.copy()crea una copia profunda contraria a Object.assign(). Si desea una copia profunda, use lodash _.cloneDeep(value)lodash.com/docs#cloneDeep
bertrandg
en Webstorm obtuve Unresolved function or method assign(); Detalles del IDE: Webstorm 2016.2. ¿Cómo puedo resolver eso?
mihai
2
@meorfi Ir a File -> Settings -> Languages & Frameworks -> Javascripty establecer Javascript language versionen ECMAScript 6.0.
Siri0S
@bertrandg _.clone (valor) es diferente a angular.copy (), no creará una nueva instancia, por lo que _.cloneDeep (valor) seguirá creando una referencia stackoverflow.com/questions/26411754/…
Zealitude
55
Además, si está copiando una matriz, use:const copy = [ ...original ]
daleyjem
43
Hasta que tengamos una mejor solución, puede usar lo siguiente:
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.
esto arruina tus citas y es lento como el infierno.
LanderV
55
Sin embargo, no es tan lento como importar una biblioteca completa para hacer una sola tarea, siempre que lo que esté haciendo sea bastante simple ...
Ian Belcher
1
esto es horrible, nunca uses eso
Murhaf Sousli
1
@MurhafSousli, intenta comprender el contexto de esta respuesta. Esto se proporcionó cuando Angular 2 estaba en desarrollo, y la esperanza era que eventualmente obtendríamos un equivalente de la función angular.copy (). Para cerrar el período de espera, pongo esta solución como una opción temporal hasta que tengamos una mejor solución. Esta es una línea con clonación profunda. Esto es horrible , estoy de acuerdo ... Pero dado el contexto experimental en ese momento, no es tan malo.
Mani
1
@ LazarLjubenović, por supuesto, en 2018 ese es el caso y estoy totalmente de acuerdo con usted hoy , pero en 2016 el paquete web no tuvo sacudidas de árboles, por lo que en la mayoría de los casos importaría una biblioteca completa.
Ian Belcher
22
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í:
Instalar lodash con yarn add lodashonpm install lodash .
En su componente, impórtelo cloneDeepy úselo:
import { cloneDeep } from "lodash";
...
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.
¿Se agregaron "solo 18kb" a la salida para poder copiar objetos en profundidad? JavaScript es un desastre.
Endrju
Después de leer su artículo referenciado, entiendo que el cloneDeepmétodo crea una instancia de un nuevo objeto. ¿Deberíamos seguir usándolo si ya tenemos un objeto de destino?
Stephane
17
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
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.
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 !
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.
}
// para desvincular fechas podemos agregar: if (Object.prototype.toString.call (obj) === '[fecha del objeto]') {return new Date (obj.getTime ()); }
A_J
1
o verifique la fecha usando el tipo de instancia - if (obj instanceof Date) {return new Date (obj.getTime ())}
Anoop Isaac
0
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. He creado una esencia para esto.
He creado un servicio para usar con Angular 5 o superior, usa la angular.copy ()base de angularjs, funciona bien para mí. Además, hay otras funciones como isUndefined, etc. Espero que sea útil. Como cualquier optimización, sería bueno saberlo. Saludos
import{Injectable}from'@angular/core';@Injectable({providedIn:'root'})exportclassAngularService{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'){returntrue;}else{returnfalse;}}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){returntypeof 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){returntypeof 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]));}}elseif(this.isBlankObject(source)){for(const key ofObject.keys(source)){
destination[key]=this.copyElement(source[key]);}}elseif(source &&typeof source.hasOwnProperty ==='function'){for(const key ofObject.keys(source)){
destination[key]=this.copyElement(source[key]);}}else{for(const key ofObject.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){returnthis.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]':returnnew source.constructor(this.copyElement(source.buffer), source.byteOffset, source.length);case'[object ArrayBuffer]':if(!source.slice){const copied =newArrayBuffer(source.byteLength);newUint8Array(copied).set(newUint8Array(source));return copied;}return source.slice(0);case'[object Boolean]':case'[object Number]':case'[object String]':case'[object Date]':returnnew source.constructor(source.valueOf());case'[object RegExp]':const re =newRegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;return re;case'[object Blob]':returnnew 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);returnthis.copyRecurse(source, destination);}returnthis.copyElement(source);}}
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:
.copy()
pero en realidad no lo necesitaría. En varios proyectos de AngJS1 que he visto, fue una exageración, donde una copia manual de las subestructuras relevantes habría hecho un código más limpio. Tal vez eso fue parte de la decisión de no implementarlo por el equipo de Angular.Respuestas:
Suponiendo que está utilizando ES6, puede usar
var copy = Object.assign({}, original)
. Funciona en navegadores modernos; si necesita admitir navegadores antiguos, consulte este polyfillactualizar:
Con TypeScript 2.1+, la notación abreviada de objetos ES6 está disponible:
fuente
angular.copy()
crea una copia profunda contraria aObject.assign()
. Si desea una copia profunda, use lodash_.cloneDeep(value)
lodash.com/docs#cloneDeepUnresolved function or method assign()
; Detalles del IDE: Webstorm 2016.2. ¿Cómo puedo resolver eso?File -> Settings -> Languages & Frameworks -> Javascript
y establecerJavascript language version
enECMAScript 6.0
.const copy = [ ...original ]
Hasta que tengamos una mejor solución, puede usar lo siguiente:
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.
fuente
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í:
Instalar lodash con
yarn add lodash
onpm install lodash
.En su componente, impórtelo
cloneDeep
y úselo: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.
fuente
cloneDeep
método crea una instancia de un nuevo objeto. ¿Deberíamos seguir usándolo si ya tenemos un objeto de destino?Para una copia superficial , puede usar Object.assign, que es una función de ES6
NO lo use para clonación profunda
fuente
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.
https://lodash.com/docs#cloneDeep
fuente
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 {}):
fuente
La solución más simple que he encontrado es:
* PASOS IMPORTANTES: Debe instalar lodash para usar esto (que no estaba claro en otras respuestas):
y luego impórtalo en tu archivo ts:
fuente
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:
Eso es lo que decidimos hacer.
fuente
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. He creado una esencia para esto.
fuente
Tuve el mismo problema y no quería usar ningún complemento solo para una clonación profunda:
Créditos: Hice esta función más legible , verifique las excepciones a su funcionalidad a continuación
fuente
He creado un servicio para usar con Angular 5 o superior, usa la
angular.copy ()
base de angularjs, funciona bien para mí. Además, hay otras funciones comoisUndefined
, etc. Espero que sea útil. Como cualquier optimización, sería bueno saberlo. Saludosfuente
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:
fuente
El
JSON.stringify()
método convierte un objeto o valor de JavaScript en una cadena JSONfuente
Puedes clonar la matriz como
Y clonar el objeto como
fuente
Si aún no está usando lodash, no recomendaría instalarlo solo para este método. En cambio, sugiero una biblioteca más especializada como 'clon':
fuente