Em muitas situações, você pode querer usar, .copy()mas na verdade não precisaria. Em vários projetos do AngJS1 que eu vi, foi um exagero, onde uma cópia manual das subestruturas relevantes teria criado um código mais limpo. Talvez isso tenha sido parte da decisão de não implementá-lo pela equipe Angular.
Supondo que você esteja usando o ES6, você pode usá-lo var copy = Object.assign({}, original). Funciona em navegadores modernos; se você precisar oferecer suporte a navegadores antigos, confira este polyfill
atualizar:
Com o TypeScript 2.1+, a notação abreviada de objeto ES6 está disponível:
Observe que angular.copy()cria uma cópia profunda contrária a Object.assign(). Se você quiser profunda cópia utilização lodash _.cloneDeep(value)lodash.com/docs#cloneDeep
bertrandg
no Webstorm eu consegui Unresolved function or method assign(); Detalhes do IDE: Tempestade na Web 2016.2. Como posso resolver isso?
mihai
2
@meorfi Vá para File -> Settings -> Languages & Frameworks -> Javascripte defina Javascript language versioncomo ECMAScript 6.0.
Siri0S
@bertrandg _.clone (value) é diferente de angular.copy (), ele não criará uma nova instância; portanto, como _.cloneDeep (value) ele ainda criará uma referência stackoverflow.com/questions/26411754/…
Zealitude
5
Além disso, se você estiver copiando uma matriz, use:const copy = [ ...original ]
daleyjem
43
Até termos uma solução melhor, você pode usar o seguinte:
Observação: a solução acima foi projetada apenas para ser um liner de correção rápida, fornecido no momento em que o Angular 2 estava em desenvolvimento ativo. Minha esperança era que pudéssemos obter um equivalente angular.copy(). Portanto, eu não queria escrever ou importar uma biblioteca de clonagem profunda.
Este método também possui problemas com a análise das propriedades da data (ele se tornará uma sequência).
Por favor, não use esse método em aplicativos de produção . Use-o apenas em seus projetos experimentais - aqueles que você está fazendo para aprender o Angular 2.
Não tão lento como a importação de uma biblioteca inteira para fazer uma única tarefa, porém, contanto que você está fazendo é muito simples ...
Ian Belcher
1
isto é horrível, nunca use que
Murhaf Sousli
1
@MurhafSousli, tente entender o contexto desta resposta. Isso foi fornecido quando o Angular 2 estava em desenvolvimento, e a esperança era que, eventualmente, obtivéssemos um equivalente à função angular.copy (). Para preencher o período de espera, coloquei essa solução como uma opção temporária até termos uma solução melhor. Este é um one-liner com clonagem profunda. Isso é horrível , eu concordo ... Mas, dado o contexto experimental da época, não é tão ruim assim.
Mani
1
@ LazarLjubenović, é claro que em 2018 é esse o caso e concordo totalmente com você hoje , mas em 2016 o webpack não tinha tremores de árvores, então você importaria uma biblioteca inteira na maioria dos casos.
Ian Belcher
22
A alternativa para copiar objetos com objetos aninhados é usar o método cloneDeep do lodash.
Para Angular, você pode fazer assim:
Instale o lodash com yarn add lodashou npm install lodash.
No seu componente, importe cloneDeepe use-o:
import { cloneDeep } from "lodash";
...
clonedObject = cloneDeep(originalObject);
São apenas 18kb adicionados à sua compilação, vale a pena pelos benefícios.
Também escrevi um artigo aqui , se você precisar de mais informações sobre o porquê do uso do cloneDeep do lodash.
Use lodash como bertandg indicado. O motivo pelo qual o angular não possui mais esse método é porque o angular 1 era uma estrutura independente e as bibliotecas externas frequentemente enfrentavam problemas com o contexto de execução angular. O Angular 2 não tem esse problema; portanto, use a biblioteca que você deseja.
Se você deseja copiar uma instância de classe, também pode usar Object.assign, mas precisa passar uma nova instância como primeiro parâmetro (em vez 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 outros já apontaram, usar lodash ou sublinhado é provavelmente a melhor solução. Mas se você não precisar dessas bibliotecas para mais nada, provavelmente poderá usar algo como isto:
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 datas, podemos adicionar: if (Object.prototype.toString.call (obj) === '[data do objeto]') {return new Date (obj.getTime ()); }
A_J 7/11
1
ou verifique a data usando o tipo de instância - if (obj instanceof Date) {return new Date (obj.getTime ())}
Anoop Isaac
0
Eu precisava desse recurso apenas para formar 'modelos' do meu aplicativo (dados de back-end brutos convertidos em objetos). Então, acabei usando uma combinação de Object.create (criar novo objeto a partir do protótipo especificado) e Object.assign (copiar propriedades entre objetos). Precisa lidar com a cópia profunda manualmente. Eu criei uma essência para isso.
Eu criei um serviço para usar com o Angular 5 ou superior, ele usa a angular.copy ()base do angularjs, funciona bem para mim. Além disso, existem outras funções como isUndefined, etc. Espero que ajude. Como qualquer otimização, seria bom saber. Saudações
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);}}
Eu e você também enfrentamos um problema do trabalho angular.copy e angular.expect porque eles não copiam o objeto ou criam o objeto sem adicionar algumas dependências. Minha solução foi esta:
Se você ainda não estiver usando o lodash, eu não recomendaria instalá-lo apenas para este método. Sugiro uma biblioteca mais restrita, como o 'clone':
.copy()
mas na verdade não precisaria. Em vários projetos do AngJS1 que eu vi, foi um exagero, onde uma cópia manual das subestruturas relevantes teria criado um código mais limpo. Talvez isso tenha sido parte da decisão de não implementá-lo pela equipe Angular.Respostas:
Supondo que você esteja usando o ES6, você pode usá-lo
var copy = Object.assign({}, original)
. Funciona em navegadores modernos; se você precisar oferecer suporte a navegadores antigos, confira este polyfillatualizar:
Com o TypeScript 2.1+, a notação abreviada de objeto ES6 está disponível:
fonte
angular.copy()
cria uma cópia profunda contrária aObject.assign()
. Se você quiser profunda cópia utilização lodash_.cloneDeep(value)
lodash.com/docs#cloneDeepUnresolved function or method assign()
; Detalhes do IDE: Tempestade na Web 2016.2. Como posso resolver isso?File -> Settings -> Languages & Frameworks -> Javascript
e definaJavascript language version
comoECMAScript 6.0
.const copy = [ ...original ]
Até termos uma solução melhor, você pode usar o seguinte:
EDIT: Esclarecimento
Observação: a solução acima foi projetada apenas para ser um liner de correção rápida, fornecido no momento em que o Angular 2 estava em desenvolvimento ativo. Minha esperança era que pudéssemos obter um equivalente
angular.copy()
. Portanto, eu não queria escrever ou importar uma biblioteca de clonagem profunda.Este método também possui problemas com a análise das propriedades da data (ele se tornará uma sequência).
Por favor, não use esse método em aplicativos de produção . Use-o apenas em seus projetos experimentais - aqueles que você está fazendo para aprender o Angular 2.
fonte
A alternativa para copiar objetos com objetos aninhados é usar o método cloneDeep do lodash.
Para Angular, você pode fazer assim:
Instale o lodash com
yarn add lodash
ounpm install lodash
.No seu componente, importe
cloneDeep
e use-o:São apenas 18kb adicionados à sua compilação, vale a pena pelos benefícios.
Também escrevi um artigo aqui , se você precisar de mais informações sobre o porquê do uso do cloneDeep do lodash.
fonte
cloneDeep
método instancia um novo objeto. Ainda devemos usá-lo se já tivermos um objeto de destino?Para cópia superficial, você pode usar Object.assign, que é um recurso do ES6
NÃO o use para clonagem profunda
fonte
Use lodash como bertandg indicado. O motivo pelo qual o angular não possui mais esse método é porque o angular 1 era uma estrutura independente e as bibliotecas externas frequentemente enfrentavam problemas com o contexto de execução angular. O Angular 2 não tem esse problema; portanto, use a biblioteca que você deseja.
https://lodash.com/docs#cloneDeep
fonte
Se você deseja copiar uma instância de classe, também pode usar Object.assign, mas precisa passar uma nova instância como primeiro parâmetro (em vez de {}):
fonte
A solução mais simples que encontrei é:
* ETAPAS IMPORTANTES: Você deve instalar o lodash para usá-lo (o que não é claro em outras respostas):
e importe-o no seu arquivo ts:
fonte
Como outros já apontaram, usar lodash ou sublinhado é provavelmente a melhor solução. Mas se você não precisar dessas bibliotecas para mais nada, provavelmente poderá usar algo como isto:
Foi o que decidimos fazer.
fonte
Eu precisava desse recurso apenas para formar 'modelos' do meu aplicativo (dados de back-end brutos convertidos em objetos). Então, acabei usando uma combinação de Object.create (criar novo objeto a partir do protótipo especificado) e Object.assign (copiar propriedades entre objetos). Precisa lidar com a cópia profunda manualmente. Eu criei uma essência para isso.
fonte
Tinha o mesmo problema e não queria usar nenhum plug-in apenas para clonagem profunda:
Créditos: Tornei esta função mais legível . Verifique as exceções à sua funcionalidade abaixo
fonte
Eu criei um serviço para usar com o Angular 5 ou superior, ele usa a
angular.copy ()
base do angularjs, funciona bem para mim. Além disso, existem outras funções comoisUndefined
, etc. Espero que ajude. Como qualquer otimização, seria bom saber. Saudaçõesfonte
Eu e você também enfrentamos um problema do trabalho angular.copy e angular.expect porque eles não copiam o objeto ou criam o objeto sem adicionar algumas dependências. Minha solução foi esta:
fonte
O
JSON.stringify()
método converte um objeto ou valor JavaScript em uma sequência JSONfonte
Você pode clonar a matriz como
E clonar o objeto como
fonte
Se você ainda não estiver usando o lodash, eu não recomendaria instalá-lo apenas para este método. Sugiro uma biblioteca mais restrita, como o 'clone':
fonte