En programación, la mutación de objetos implica que el estado o los datos de un objeto son modificados después de su creación. En otras palabras, la operación que cambia los atributos de un objeto en JavaScript se conoce como mutación de objetos. La mutación de objetos altera directamente los valores de un objeto, lo que lo hace desafiante, especialmente en aplicaciones donde múltiples operaciones pueden intentar leer o escribir en un objeto simultáneamente.
Este artículo presenta una discusión sobre la mutación de objetos en JavaScript con ejemplos de código relevantes cuando sea necesario.
Tipos de Datos en JavaScript
Los tipos de datos denotan el tipo de datos que una variable u objeto puede contener. JavaScript soporta dos categorías distintas de tipos de datos: primitivos y definidos por el usuario o tipos de referencia.
Tipos de Datos Primitivos
En JavaScript, todos los tipos de datos primitivos son inmutables por naturaleza, es decir, no se pueden modificar después de haber sido creados. Números, Booleanos, Cadenas de Texto, Bigints, Indefinidos, Nulos, Símbolos y Objetos son ejemplos de tipos primitivos.
Tipos de Datos Definidos por el Usuario o de Referencia
Los tipos de datos definidos por el usuario o tipos de referencia son objetos creados utilizando tipos primitivos o una combinación de tipos primitivos y definidos por el usuario. Ejemplos típicos de tipos de referencia o definidos por el usuario son objetos y arreglos.
Cómo se Asignan y Reasignan Variables en JavaScript
Cuando asignas una variable de tipo primitivo a una variable de tipo primitivo, las dos variables contienen valores similares, pero se almacenan en ubicaciones de almacenamiento diferentes. Por ejemplo, supongamos que tienes dos variables varA
y varB
y asignas una variable a otra de la siguiente manera:
var varA = 100;
var varB = varA;
console.log(varB);
Cuando ejecutas el fragmento de código anterior, se mostrará el número 100 en la consola. Ahora, cambias los valores de una de las dos variables (digamos varB
) de la siguiente manera:
var varA = 100;
var varB = varA;
varB = 500;
console.log(varA);
Observa cómo se ha cambiado el valor de la variable varB
a 500. Cuando imprimes el valor de varA
, seguirá mostrando 100. Esto se debe a que estas variables varA
y varB
se almacenan en dos ubicaciones de memoria diferentes. Por lo tanto, si cambias alguna de ellas, el nuevo o cambiado valor no se reflejará en las otras variables.
¿Qué es la Mutación de Objetos en JavaScript?
En JavaScript, el tipo de datos de un objeto puede pertenecer a cualquiera de las dos categorías: primitivo o no primitivo. Mientras que los tipos primitivos son inmutables, es decir, no puedes cambiarlos después de crearlos, puedes alterar los tipos no primitivos, es decir, objetos y arreglos. Los objetos siempre permiten cambiar sus valores. Por lo tanto, puedes cambiar el estado de los campos de un tipo mutable sin crear una nueva instancia.
Las mutaciones de objetos pueden crear varios problemas, como los siguientes:
- Los objetos mutados a menudo pueden provocar condiciones de carrera debido a problemas de concurrencia y seguridad de hilos
- La mutación puede introducir complejidades en el código fuente debido a problemas de previsibilidad y seguridad en hilos
- La mutación a menudo puede llevar a errores que pueden ser difíciles de identificar en el código fuente de la aplicación
- La mutación dificulta las pruebas y depuración del código porque rastrear el código que aprovecha la mutación se convierte en un desafío
Ejemplos de código que demuestran la mutación de objetos
La mutación de objetos puede ocurrir en cualquiera de los siguientes escenarios:
- Agregar, editar o eliminar propiedades
- Usar métodos que pueden mostrar mutación
Cuando modificas las propiedades de un objeto, ya sea directa o indirectamente, estás mutando el objeto. El siguiente fragmento de código muestra cómo puedes mutar un objeto cambiando su propiedad.
const author = { id: 1, name: "Joydip Kanjilal"};
author.id = 2; author.city = "Hyderabad, INDIA";
console.log(author);
En el fragmento de código anterior, creamos un objeto llamado autor que contiene dos propiedades, a saber, id
y name
. Mientras que la propiedad id
se utiliza para almacenar el id
del registro del autor, la propiedad name
almacena el nombre del autor. Observa cómo mutamos el objeto autor al alterar el valor relativo a la propiedad id
. A continuación, agregamos una nueva propiedad, llamada city, al objeto autor y asignamos un valor a la propiedad.
Cuando ejecutas el fragmento de código anterior, las propiedades y sus valores del objeto autor se mostrarán como se muestra a continuación:
{ name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA' }
Cuando pasas un objeto a una función o lo asignas a una variable en JavaScript, básicamente estás pasando la referencia al objeto y no una copia de este. Esto implica que cualquier cambio que realices en el nuevo objeto creado al pasar un objeto o asignarlo a la variable se aplicará a todas las referencias del objeto real.
Considera el siguiente fragmento de código que muestra cómo puedes crear un objeto en JavaScript y luego asignarlo a una variable.
const objA = { id: 1, name: 'Joydip Kanjilal',
city: 'Hyderabad, INDIA', pincode: 500089 }
const objB = objA;
objB.pincode = 500034;
console.log(objA);
En el fragmento de código anterior, el objeto objA
se asigna a objB
, y se cambia el valor de la propiedad pincode de objA
, es decir, el objeto objA
se muta. Cuando ejecutas el programa, se mostrarán los siguientes datos.
{ id: 1, name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA', pincode: 500034 }
Observa que el valor de la propiedad pincode ha sido modificado.
Evitar la Mutación de Objetos en JavaScript
En JavaScript, puedes evitar la mutación de varias maneras, tales como las siguientes:
- Utilizando la clonación de objetos aprovechando el método
Object.assign()
o el operador de propagación (…) - Utilizando el método
Object.seal()
para prevenir la adición o eliminación de propiedades de un objeto - Utilizando el método
Object.freeze()
para prevenir la adición, edición o eliminación de propiedades de un objeto
Usando Clonación
Consulta el siguiente fragmento de código que muestra cómo puedes clonar un objeto en JavaScript utilizando el operador de propagación.
let originalObj = { x: 10, y: 100 }; let clonedObj = { originalObj };
Aquí, el nombre del objeto clonado es clonedObj
, y es idéntico al objeto original llamado originalObj
. Entonces, si muestras los valores de las dos propiedades de estos dos objetos, los resultados serán iguales.
Ahora, cambia el valor de una de las propiedades del objeto clonado llamado clonedObj
a tu valor deseado, como se muestra en el fragmento de código dado a continuación.
clonedObj.x = 50;
Ahora, escribe el siguiente fragmento de código para mostrar el valor de la propiedad llamada x
referente a los dos objetos originalObj
y clonedObj
.
console.log(originalObj.x);
console.log(clonedObj.x);
Cuando ejecutes el programa, observarás que el valor de la propiedad x
en el objeto original no ha cambiado. Los valores se mostrarán en la consola como se muestra a continuación:
10
50
Usando el Método Object.freeze()
El método Object.freeze()
puede hacer que un objeto sea inmutable al evitar cualquier alteración en cualquiera de sus propiedades.
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);
Cuando ejecutas el fragmento de código anterior, los resultados serán similares a esto:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Hyderabad',
state: 'Telangana',
country: 'India',
pincode: 500089
}
Como puedes ver en la salida, incluso si has asignado valores a las propiedades city y state, y pincode, no hay efecto. Por lo tanto, no se han realizado cambios en los datos contenidos en ninguna de las propiedades del objeto.
Usando el Método Object.seal()
También puedes utilizar el método Object.seal()
para prevenir la mutación de objetos en JavaScript. Este método te permitiría alterar los valores de propiedades existentes, pero no puedes modificar o eliminar ninguna de las propiedades del Objeto. El siguiente ejemplo de código ilustra esto:
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);
En el fragmento de código anterior, si bien se permitirán modificaciones a las propiedades del objeto llamado autor, no se permitirá ni la adición ni la eliminación de las propiedades del objeto. Al ejecutar el programa, verás que los valores de las propiedades modificadas se reflejan en el resultado, pero las instrucciones que añaden o eliminan propiedades son ignoradas. Así es como se vería la salida en la consola:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Bangalore',
state: 'Karnataka',
country: 'India',
pincode: 560005
}
Usando el método Object.defineProperty()
También puedes aprovechar el método Object.defineProperty()
en JavaScript para controlar la mutabilidad de las propiedades individuales de un objeto. El siguiente fragmento de código muestra cómo puedes utilizar este método para prohibir alteraciones al valor contenido en una propiedad cuya mutabilidad está restringida.
const author = { id: 1, name: "Joydip Kanjilal"};
Object.defineProperty(author, "booksauthored",
{
value: 3,
writable: false,
});
author.booksauthored = 5;
console.log(author.booksauthored);
Al ejecutar el fragmento de código anterior, verás que se muestra el número 3 en la consola.
Aspectos clave
- JavaScript categoriza los tipos de objetos en dos categorías distintas: primitivos (mutables) y objetos (inmutables).
- El término mutación de objeto se refiere a las operaciones que alteran o cambian un objeto después de haber sido creado.
- Aunque los valores primitivos como números, etc., no pueden ser alterados, siempre puedes cambiar objetos después de que han sido creados.
- Dado que las cadenas en JavaScript son inmutables, no puedes alterarlas una vez que han sido creadas.
- Aunque la mutación en sí misma no es tan mala, debes gestionarla cuidadosamente para reducir errores en tus aplicaciones.
- Puedes reducir o eliminar la mutación en JavaScript siguiendo las prácticas recomendadas y aprovechando las estructuras de datos inmutables.
Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript