Copiando e Comparando Objetos em JavaScript
Copiando Objetos
Ao contrário dos dados de tipos primitivos, os dados dos objetos são copiados por referência. O que isso significa? Vamos considerar o seguinte exemplo:
const tom = { name: "Tom" };
const bob = tom;
// verificamos a propriedade name em ambas as constantes
console.log(tom.name); // Tom
console.log(bob.name); // Tom
// alteramos a propriedade name na constante bob
bob.name = "Bob";
// verificamos novamente a propriedade name em ambas as constantes
console.log("Após a mudança");
console.log(tom.name); // Bob
console.log(bob.name); // BobInicialmente, um objeto comum tom é definido com uma propriedade name. Então, o valor desse objeto é atribuído à constante bob:
const bob = tom;Neste caso, a constante bob recebe uma referência ou, por assim dizer, o endereço da constante tom, portanto, após essa atribuição, ambas as constantes essencialmente apontam para o mesmo objeto na memória. Consequentemente, as mudanças feitas através de uma constante:
bob.name = "Bob";Serão refletidas na outra constante:
console.log(tom.name); // BobAlém disso, vamos adicionar uma nova propriedade ao objeto por meio de uma das constantes:
const tom = { name: "Tom" };
const bob = tom;
// adicionamos à constante bob uma nova propriedade - age
bob.age = 37;
// e vemos que para tom também foi adicionada uma nova propriedade
console.log(tom.age); // 37Após adicionar a propriedade age à constante bob, podemos ver que na constante tom essa propriedade também apareceu, porque novamente ambas as constantes representam o mesmo objeto.
Mas e se quisermos copiar de uma propriedade do objeto, mas ao mesmo tempo ambas as constantes ou variáveis apontassem para objetos completamente diferentes, mudanças em um dos quais de forma alguma afetariam o outro? Nesse caso, podemos usar o método integrado Object.assign().
Método Object.assign
O método Object.assign() aceita dois parâmetros:
Object.assign(target, ...sources);O primeiro parâmetro target representa o objeto ao qual as propriedades devem ser copiadas. O segundo parâmetro ...sources é um conjunto de objetos dos quais as propriedades devem ser copiadas (ou seja, podemos copiar propriedades de vários objetos ao mesmo tempo)
O método retorna o objeto target, no qual as propriedades dos objetos sources foram copiadas.
Por exemplo:
const tom = { name: "Tom", age: 37 };
const bob = Object.assign({}, tom);
bob.name = "Bob";
bob.age = 41;
console.log(`Objeto tom. Name: ${tom.name} Age: ${tom.age}`);
console.log(`Objeto bob. Name: ${bob.name} Age: ${bob.age}`);Neste caso, a chamada Object.assign({}, tom) significa que estamos copiando dados do objeto tom para um objeto vazio {}. O resultado dessa cópia foi o objeto bob. E este é um objeto completamente diferente de tom. E quaisquer alterações na constante bob aqui de forma alguma afetarão a constante tom.
Saída no console do navegador:
Objeto tom. Name: Tom Age: 37 Objeto bob. Name: Bob Age: 41
Copiando de Vários Objetos
Da mesma forma, podemos copiar dados de vários objetos:
const tom = { name: "Tom" };
const sam = { age: 37 };
const person = { height: 170 };
Object.assign(person, tom, sam); // copiamos de tom e sam para person
console.log(person); // { height: 170, name: "Tom", age: 37 }Aqui, todas as propriedades dos objetos tom e sam são copiadas para o objeto person. Como resultado, após a cópia, o objeto person terá três propriedades.
Copiando Propriedades com o Mesmo Nome
Se os objetos dos quais a cópia é realizada contêm propriedades iguais, as propriedades dos objetos mais recentes substituirão as propriedades dos anteriores:
const tom = { name: "Tom", age: 37 };
const sam = { age: 45 };
const person = { height: 170 };
Object.assign(person, tom, sam);
console.log(person); // { height: 170, name: "Tom", age: 45 }Aqui, ambos os objetos tom e sam contêm a propriedade age, mas no objeto person, a propriedade age é 45, que é o valor do objeto sam, porque a cópia do objeto sam é feita por último.
Copiando Propriedades-Objeto
Embora o Object.assign() funcione bem para objetos simples, o que acontece se a propriedade do objeto copiado também for um objeto:
const tom = { name: "Tom", company: { title: "Microsoft" } };
const bob = Object.assign({}, tom);
bob.name = "Bob";
bob.company.title = "Google";
console.log(tom.name); // Tom
console.log(tom.company.title); // GoogleAqui, a propriedade company do objeto tom é um objeto com uma propriedade. E na cópia, o objeto bob recebe não uma cópia do valor tom.company, mas uma referência a esse objeto. Portanto, mudanças em bob.company afetarão tom.company.
Copiando Objeto com o Operador Spread
O operador spread ... permite desmembrar um objeto em diversos pares propriedade-valor, que podem ser passados a outro objeto:
const tom = { name: "Tom", age: 37, company: "Google" };
const bob = { ...tom };
bob.name = "Bob";
console.log(tom); // { name: "Tom", age: 37, company: "Google" }
console.log(bob); // { name: "Bob", age: 37, company: "Google" }Neste caso, ao objeto bob são passadas cópias das propriedades do objeto tom.
Se algumas propriedades do novo objeto devem ter outros valores (como no exemplo acima a propriedade name), elas podem ser especificadas no final:
const tom = { name: "Tom", age: 37, company: "Google" };
const bob = { ...tom, name: "Bob" };
console.log(bob); // { name: "Bob", age: 37, company: "Google" }Como visto no exemplo anterior, ambas as constantes após a cópia representam links para diferentes objetos, e mudanças em um deles de forma alguma afetarão o outro objeto.
No entanto, se os objetos contêm objetos aninhados, esses objetos aninhados, ao serem copiados, novamente, na verdade representarão links para o mesmo objeto:
const tom = { name: "Tom", age: 37, company: { title: "Microsoft" } };
const bob = { ...tom };
bob.name = "Bob";
bob.company.title = "Google";
console.log(`${tom.name} - ${tom.company.title}`); // Tom - Google
console.log(`${bob.name} - ${bob.company.title}`); // Bob - GoogleComparação de Objetos
Vamos comparar dois objetos usando as operações padrão de comparação e equivalência:
const tom = { name: "Tom" };
const bob = { name: "Bob" };
console.log(tom == bob); // false
console.log(tom === bob); // falseAmbos os operadores, neste caso, retornarão false, ou seja, os objetos não são iguais. Mesmo que os valores das propriedades dos objetos sejam iguais, ainda assim, em ambos os casos, obteremos false:
const tom = { name: "Tom" };
const bob = { name: "Tom" };
console.log(tom == bob); // false
console.log(tom === bob); // falseNo entanto, o que acontecerá se ambas as constantes (variáveis) armazenarem uma referência para o mesmo objeto:
const tom = { name: "Tom" };
const bob = tom;
console.log(tom == bob); // true
console.log(tom === bob); // trueNeste caso, ambos os operadores retornarão true, porque ambas as constantes tom e bob armazenam uma referência para o mesmo objeto.