Skip to content
Skip to content
Menu
Info Cafe
Info Cafe

Copiar Objectos em JavaScript

By admin on Janeiro 10, 2021

Objectos são os blocos fundamentais do JavaScript. Um objecto é uma colecção de propriedades, e uma propriedade é uma associação entre uma chave (ou nome) e um valor. Quase todos os objectos em JavaScript são instâncias de Object que se situa no topo da cadeia do protótipo.

Introdução

Como sabe, o operador de atribuição não cria uma cópia de um objecto, apenas lhe atribui uma referência, vejamos o seguinte código:

let obj = { a: 1, b: 2,};let copy = obj;obj.a = 5;console.log(copy.a);// Result // a = 5;

O obj variável é um recipiente para o novo objecto inicializado. A variável copy está a apontar para o mesmo objecto e é uma referência a esse objecto. Assim, basicamente este { a: 1, b: 2, } objecto está a dizer: Há agora duas maneiras de ter acesso a mim. Tem de passar pela variável obj ou pela variável copy de uma ou de outra forma que ainda me atinge e tudo o que me fizer através destas vias (gateways) afectar-me-á.

A imutabilidade é amplamente falada nos dias de hoje e tem de ouvir esta chamada! Este método remove qualquer forma de imutabilidade e pode levar a bugs caso o objecto original seja usado por outra parte do seu código.

A forma ingénua de copiar objectos

A forma ingénua de copiar objectos é fazer looping através do objecto original e copiar cada propriedade uma após a outra. Vamos dar uma olhada neste código:

function copy(mainObj) { let objCopy = {}; // objCopy will store a copy of the mainObj let key; for (key in mainObj) { objCopy = mainObj; // copies each property to the objCopy object } return objCopy;}const mainObj = { a: 2, b: 5, c: { x: 7, y: 4, },}console.log(copy(mainObj));

Questões Inerentes

  1. objCopy objecto tem um novo Object.prototype método diferente do mainObj método de protótipo de objecto, que não é o que queremos. Queremos uma cópia exacta do objecto original.
  2. Os descritores de propriedade não são copiados. Um descritor “gravável” com valor definido para ser falso será verdadeiro no objCopy object.
  3. O código acima apenas copia propriedades enumeradas de mainObj.
  4. Se uma das propriedades do objecto original for um objecto em si, então será partilhada entre a cópia e o original fazendo com que as suas respectivas propriedades apontem para o mesmo objecto.

Objectos de Cópia Rápida

Diz-se que um objecto é copiado pouco profundo quando as propriedades de nível superior da fonte são copiadas sem qualquer referência e existe uma propriedade de origem cujo valor é um objecto e é copiado como referência. Se o valor da fonte for uma referência a um objecto, apenas copia esse valor de referência para o objecto de destino.

Uma cópia rasa duplicará as propriedades de nível superior, mas o objecto aninhado é partilhado entre o original (fonte) e a cópia (alvo).

Using Object.assign() method

O método Object.assign() é usado para copiar os valores de todas as propriedades próprias enumeradas de um ou mais objectos-fonte para um objecto-alvo.

let obj = { a: 1, b: 2,};let objCopy = Object.assign({}, obj);console.log(objCopy);// Result - { a: 1, b: 2 }

Bem, isto faz o trabalho até agora. Fizemos uma cópia de obj. Vamos ver se a imutabilidade existe:

let obj = { a: 1, b: 2,};let objCopy = Object.assign({}, obj);console.log(objCopy); // result - { a: 1, b: 2 }objCopy.b = 89;console.log(objCopy); // result - { a: 1, b: 89 }console.log(obj); // result - { a: 1, b: 2 }

No código acima, alterámos o valor da propriedade 'b' em objCopy objecto para 89 e quando registamos o objecto modificado objCopy na consola, as alterações aplicam-se apenas a objCopy. A última linha de código verifica que o objecto obj ainda está intacto e não mudou. Isto implica que criámos com sucesso uma cópia do objecto fonte sem quaisquer referências a ele.

Pitfall of Object.assign()

Não tão depressa! Embora tenhamos criado com sucesso uma cópia e tudo pareça estar a funcionar bem, lembram-se que discutimos a cópia superficial? Vejamos este exemplo:

let obj = { a: 1, b: { c: 2, },}let newObj = Object.assign({}, obj);console.log(newObj); // { a: 1, b: { c: 2} }obj.a = 10;console.log(obj); // { a: 10, b: { c: 2} }console.log(newObj); // { a: 1, b: { c: 2} }newObj.a = 20;console.log(obj); // { a: 10, b: { c: 2} }console.log(newObj); // { a: 20, b: { c: 2} }newObj.b.c = 30;console.log(obj); // { a: 10, b: { c: 30} }console.log(newObj); // { a: 20, b: { c: 30} }// Note: newObj.b.c = 30; Read why..

Porquê obj.b.c = 30?

p>Bem, isso é uma armadilha de Object.assign()Object.assign só faz cópias rasas. Ambos newObj.b e obj.b partilham a mesma referência ao objecto devido a não terem sido feitas cópias individuais, em vez disso foi copiada uma referência ao objecto. Qualquer alteração feita a qualquer propriedade do objecto aplica-se a todas as referências que utilizem o objecto. Como podemos corrigir isto? Continue a ler… temos uma correcção na secção seguinte.

Nota: As propriedades na cadeia de protótipos e as propriedades não utilizáveis não podem ser copiadas. Ver aqui:

let someObj = { a: 2,}let obj = Object.create(someObj, { b: { value: 2, }, c: { value: 3, enumerable: true, },});let objCopy = Object.assign({}, obj);console.log(objCopy); // { c: 3 }

  • someObj está na cadeia de protótipos do objecto para que não possa ser copiado.
  • property b é uma propriedade não enumerável.
  • property c tem um descritor de propriedade enumerável que permite que seja enumerável. É por isso que foi copiado.

Deep Copying Objects

Uma cópia profunda irá duplicar cada objecto que encontrar. A cópia e o objecto original não partilharão nada, por isso será uma cópia do original. Aqui está a solução para o problema que encontramos usando Object.assign(). Vamos explorar.

Usando JSON.parse(JSON.stringify(object));

Isto resolve o problema que tínhamos anteriormente. Agora newObj.b tem uma cópia e não uma referência! Esta é uma forma de copiar objectos em profundidade. Aqui está um exemplo:

let obj = { a: 1, b: { c: 2, },}let newObj = JSON.parse(JSON.stringify(obj));obj.b.c = 20;console.log(obj); // { a: 1, b: { c: 20 } }console.log(newObj); // { a: 1, b: { c: 2 } } (New Object Intact!)

Immutable: ✓

Pitfall

Felizmente, este método não pode ser usado para copiar métodos de objectos definidos pelo utilizador. Ver abaixo.

Cópia de métodos de objectos

Um método é uma propriedade de um objecto que é uma função. Nos exemplos até agora, ainda não copiámos um objecto com um método. Vamos tentar isso agora e usar os métodos que aprendemos a fazer cópias.

let obj = { name: 'scotch.io', exec: function exec() { return true; },}let method1 = Object.assign({}, obj);let method2 = JSON.parse(JSON.stringify(obj));console.log(method1); //Object.assign({}, obj)/* result{ exec: function exec() { return true; }, name: "scotch.io"}*/console.log(method2); // JSON.parse(JSON.stringify(obj))/* result{ name: "scotch.io"}*/

O resultado mostra que Object.assign() pode ser usado para copiar métodos enquanto JSON.parse(JSON.stringify(obj)) não pode ser usado.

Copiar objectos circulares

Objectos circulares são objectos que têm propriedades que se referem a si próprios. Vamos usar os métodos de copiar objectos que aprendemos até agora para fazer cópias de um objecto circular e ver se funciona.

Utilizar JSON.parse(JSON).stringify(object))

Tentemos JSON.parse(JSON.stringify(object)):

// circular objectlet obj = { a: 'a', b: { c: 'c', d: 'd', },}obj.c = obj.b;obj.e = obj.a;obj.b.c = obj.c;obj.b.d = obj.b;obj.b.e = obj.b.c;let newObj = JSON.parse(JSON.stringify(obj));console.log(newObj); 

Aqui está o resultado:

JSON.parse(JSON.stringify(obj)) claramente não funciona para objectos circulares.

Using Object.assign()

P>Tentemos Object.assign():

// circular objectlet obj = { a: 'a', b: { c: 'c', d: 'd', },}obj.c = obj.b;obj.e = obj.a;obj.b.c = obj.c;obj.b.d = obj.b;obj.b.e = obj.b.c;let newObj2 = Object.assign({}, obj);console.log(newObj2); 

Aqui está o resultado:

Object.assign() funciona bem para copiar objectos circulares pouco profundos mas não funcionaria para uma cópia profunda. Sinta-se à vontade para explorar o circular object tree na consola do seu navegador. Tenho a certeza de que encontrará aí um monte de trabalho interessante.

Using Spread Elements ( … )

ES6 já tem elementos de descanso para atribuição de desestruturação de array e elementos de spread para array literalmente implementados. Dê uma vista de olhos à implementação de elementos de propagação num array aqui:

const array = ;const newArray = ;console.log(newArray);// Result // 

A propriedade de propagação para objectos literais é actualmente uma proposta de Fase 3 para ECMAScript. As propriedades de propagação nos inicializadores de objectos copiam as próprias propriedades enumeráveis de um objecto fonte para o objecto alvo. O exemplo abaixo mostra como seria fácil copiar um objecto uma vez a proposta aceite.

let obj = { one: 1, two: 2,}let newObj = { ...z };// { one: 1, two: 2 }

Nota: Isto só será eficaz para cópia rasa

Conclusão

Copiar objectos em JavaScript pode ser bastante assustador especialmente se for novo no JavaScript e não souber o seu caminho em torno da linguagem. Espero que este artigo o tenha ajudado a compreender e evitar futuras armadilhas que poderá encontrar ao copiar objectos. Se tiver alguma biblioteca ou peça de código que alcance um melhor resultado, sinta-se bem-vindo a partilhar com a comunidade. Feliz codificação!

Navegação de artigos

Kroger Weekly Ad (2/24/21 – 3/2/2/21) & Anúncio Kroger Preview Sneak Peek
Como fazer um CD/DVD/USB bootável para instalar o Windows

Deixe uma resposta Cancelar resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

Artigos recentes

  • Firebush (Português)
  • Previsão da taxa de CD para 2021: As taxas manter-se-ão provavelmente baixas, mas poderão aumentar mais tarde no ano
  • Como estruturar a documentação do sistema de gestão da qualidade
  • Dor pélvica crónica e prostatite: sintomas, diagnóstico e tratamento
  • Mixed Berry Crisp (Português)
  • Wheat Ales (Americana)
  • Os benefícios da amamentação após um ano
  • É seguro despejar café moído na pia | Canalização atómica
  • Cool-Down After Your Workout
  • Our Work

Meta

  • Iniciar sessão
  • Feed de entradas
  • Feed de comentários
  • WordPress.org

Arquivo

  • Março 2021
  • Fevereiro 2021
  • Janeiro 2021
  • Dezembro 2020
  • DeutschDeutsch
  • NederlandsNederlands
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • PolskiPolski
  • 日本語日本語
©2021 Info Cafe | WordPress Theme by SuperbThemes.com