Na programação, a mutação de objeto implica que o estado ou dados de um objeto são alterados após a criação. Em outras palavras, a operação que muda os atributos de um objeto em JavaScript é conhecida como mutação de objeto. A mutação de objeto altera os valores de um objeto diretamente, tornando isso desafiador, especialmente em aplicações onde várias operações podem tentar ler ou gravar em um objeto simultaneamente.
Este artigo apresenta uma discussão sobre mutação de objeto em JavaScript com exemplos de código relevantes sempre que necessário.
Tipos de Dados em JavaScript
Os tipos de dados denotam o tipo de dados que uma variável ou objeto pode conter. O JavaScript suporta duas categorias distintas de tipos de dados: primitivos e tipos de referência ou definidos pelo usuário.
Tipos de Dados Primitivos
No JavaScript, todos os tipos de dados primitivos são imutáveis por natureza, ou seja, você não pode alterá-los depois que foram criados. Números, Booleans, Strings, Bigints, Undefineds, Nulls, Symbols e Objetos são exemplos de tipos primitivos.
Tipos de Dados de Referência ou Definidos pelo Usuário
Tipos de dados definidos pelo usuário ou tipos de dados de referência são objetos criados usando tipos primitivos ou uma combinação de tipos primitivos e definidos pelo usuário. Exemplos típicos de tipos de referência ou definidos pelo usuário são objetos e arrays.
Como Variáveis São Atribuídas e Reatribuídas em JavaScript
Quando você atribui uma variável de tipo primitivo a uma variável de tipo primitivo, as duas variáveis têm valores semelhantes, mas são armazenadas em locais de armazenamento diferentes. Por exemplo, suponha que você tenha duas variáveis varA e varB e atribua uma variável a outra da seguinte maneira:
var varA = 100;
var varB = varA;
console.log(varB);
Ao executar o trecho de código anterior, o número 100 será exibido no console. Agora, você altera os valores de uma das duas variáveis (digamos varB) da seguinte maneira:
var varA = 100;
var varB = varA;
varB = 500;
console.log(varA);
Observe como o valor da variável varB foi alterado para 500. Ao imprimir o valor de varA, ele ainda exibirá 100. Isso ocorre porque essas variáveis varA e varB são armazenadas em dois locais de memória diferentes. Portanto, se você alterar uma delas, o novo ou alterado valor não será refletido nas outras variáveis.
O que é Mutação de Objeto em JavaScript?
No JavaScript, o tipo de dados de um objeto pode pertencer a uma das duas categorias: primitivo ou não primitivo. Enquanto os tipos primitivos são imutáveis, ou seja, você não pode alterá-los após criá-los, você pode alterar os tipos não primitivos, ou seja, objetos e arrays. Objetos sempre permitem que seus valores sejam alterados. Portanto, você pode alterar o estado dos campos para um tipo mutável sem criar uma nova instância.
As mutações de objeto podem criar vários problemas, como os seguintes:
- Objetos mutados frequentemente podem levar a condições de corrida devido a problemas de concorrência e segurança de threads
- A mutação pode introduzir complexidades no código-fonte devido a problemas de previsibilidade e segurança de threads
- A mutação frequentemente pode levar a bugs que podem ser difíceis de identificar no código-fonte da aplicação
- A mutação torna o teste e depuração do código difícil porque rastrear o código que utiliza mutação se torna um desafio
Exemplos de Código que Demonstram a Mutação de Objetos
A mutação de objetos pode ocorrer em qualquer um dos seguintes cenários:
- Adição, edição ou remoção de propriedades
- Utilizando métodos que podem exibir mutação
Quando você altera as propriedades de um objeto, seja diretamente ou indiretamente, você está essencialmente mutando o objeto. O trecho de código a seguir mostra como você pode mutar um objeto alterando sua propriedade.
const author = { id: 1, name: "Joydip Kanjilal"};
author.id = 2; author.city = "Hyderabad, INDIA";
console.log(author);
No trecho de código anterior, criamos um objeto chamado autor que contém duas propriedades, a saber, id
e name
. Enquanto a propriedade id
é usada para armazenar o id
do registro do autor, a propriedade name
armazena o nome do autor. Observe como mutamos o objeto autor alterando o valor referente à propriedade id
. Em seguida, adicionamos uma nova propriedade, chamada city, ao objeto autor e atribuímos um valor à propriedade.
Ao executar o trecho de código anterior, as propriedades e seus valores do objeto autor serão exibidos conforme mostrado abaixo:
{ name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA' }
Quando você passa um objeto para uma função ou o atribui a uma variável em JavaScript, essencialmente está passando a referência ao objeto e não uma cópia dele. Isso implica que qualquer alteração feita no novo objeto criado ao passar um objeto ou atribuí-lo à variável se aplicará a todas as referências do objeto real.
Considere o seguinte trecho de código que mostra como você pode criar um objeto em JavaScript e então atribuí-lo a uma variável.
const objA = { id: 1, name: 'Joydip Kanjilal',
city: 'Hyderabad, INDIA', pincode: 500089 }
const objB = objA;
objB.pincode = 500034;
console.log(objA);
No trecho de código anterior, o objeto objA
é atribuído a objB
, e o valor da propriedade pincode de objA
é alterado, ou seja, o objeto objA
é mutado. Quando você executa o programa, os seguintes dados serão exibidos.
{ id: 1, name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA', pincode: 500034 }
Observe que o valor da propriedade pincode foi alterado.
Prevenindo a Mutação de Objetos em JavaScript
Em JavaScript, você pode prevenir a mutação de várias maneiras, como as seguintes:
- Usando a clonagem de objetos aproveitando o método
Object.assign()
ou o operador spread (…) - Usando o método
Object.seal()
para evitar adicionar ou excluir propriedades de um objeto - Usando o método
Object.freeze()
para evitar adicionar, editar ou excluir propriedades de um objeto
Usando Clonagem
Consulte o trecho de código a seguir que mostra como você pode clonar um objeto em JavaScript usando o operador spread.
let originalObj = { x: 10, y: 100 }; let clonedObj = { originalObj };
Aqui, o nome do objeto clonado é clonedObj
, e é idêntico ao objeto original chamado originalObj
. Portanto, se você exibir os valores das duas propriedades desses dois objetos, os resultados serão os mesmos.
Agora, altere o valor de uma das propriedades do objeto clonado chamado clonedObj
para o valor desejado, conforme mostrado no trecho de código fornecido abaixo.
clonedObj.x = 50;
Agora, escreva o seguinte trecho de código para exibir o valor da propriedade chamada x
referente aos dois objetos originalObj
e clonedObj
.
console.log(originalObj.x);
console.log(clonedObj.x);
Ao executar o programa, você observará que o valor da propriedade x
no objeto original permanece inalterado. Os valores serão exibidos no console conforme mostrado abaixo:
10
50
Usando o Método Object.freeze()
O método Object.freeze()
pode tornar um objeto imutável, impedindo quaisquer alterações em suas propriedades.
const author = { id: 1, name: "Joydip Kanjilal",
city: "Hyderabad", state: "Telengana",
country: "India", pincode: 500089};
Object.freeze(author);
author.city = "Bangalore";
author.state = "Karnataka";
author.pincode = 560010;
console.log(author);
Ao executar o trecho de código anterior, os resultados serão semelhantes a este:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Hyderabad',
state: 'Telangana',
country: 'India',
pincode: 500089
}
Como você pode ver na saída, mesmo que você tenha atribuído valores às propriedades city, state e pincode, não há efeito. Portanto, nenhuma alteração foi feita nos dados contidos em nenhuma das propriedades do objeto.
Usando o Método Object.seal()
Você também pode usar o método Object.seal()
para evitar a mutação de objetos em JavaScript. Esse método permitiria que você alterasse os valores das propriedades existentes, mas não pode modificar ou excluir nenhuma das propriedades do Objeto. O exemplo de código a seguir ilustra isso:
const author = { id: 1, name: "Joydip Kanjilal",
city: "Hyderabad", state: "Telangana",
country: "India", pincode: 500089};
Object.seal(author);
author.city = "Bangalore";
author.state = "Karnataka";
author.pincode = 560005;
author.booksauthored = 3;
console.log(author);
No trecho de código anterior, enquanto serão permitidas modificações nas propriedades do objeto chamado autor, nem a adição nem a exclusão das propriedades do objeto serão permitidas. Quando você executar o programa, verá que os valores das propriedades modificadas são refletidos no resultado, mas as declarações que adicionam ou excluem propriedades são ignoradas. Aqui está como a saída seria exibida no console:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Bangalore',
state: 'Karnataka',
country: 'India',
pincode: 560005
}
Usando o método Object.defineProperty()
Você também pode aproveitar o método Object.defineProperty()
em JavaScript para controlar a mutabilidade das propriedades individuais de um objeto. O trecho de código a seguir mostra como você pode usar esse método para proibir alterações no valor contido em uma propriedade cuja mutabilidade é restrita.
const author = { id: 1, name: "Joydip Kanjilal"};
Object.defineProperty(author, "booksauthored",
{
value: 3,
writable: false,
});
author.booksauthored = 5;
console.log(author.booksauthored);
Ao executar o trecho de código anterior, você verá o número 3 sendo exibido no console.
Principais pontos
- O JavaScript categoriza os tipos de objeto em duas categorias distintas: primitivos (mutáveis) e objetos (imutáveis).
- O termo mutação de objeto refere-se às operações que alteram ou mudam um objeto depois que ele foi criado.
- Enquanto valores primitivos como número, etc., não podem ser alterados, você sempre pode alterar objetos depois que eles foram criados.
- Uma vez que as strings em JavaScript são imutáveis, você não pode alterá-las depois que foram criadas.
- Embora a mutação por si só não seja tão ruim, você deve gerenciá-la com cuidado para reduzir bugs em suas aplicações.
- Você pode reduzir ou eliminar a mutação em JavaScript seguindo as práticas recomendadas e aproveitando estruturas de dados imutáveis.
Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript