Miguel Angel Reyes Moreno
Juan Camilo Lentino Villalba
Fredy Daniel Flores Lemus
Armando Rivera
Harold Zurita Simon
Juan Diego Mejia Maestre
Jhon Sebastián Delgado Almendrales
Miguel Angel Hernandez Colombo
Nazareno Rosales
Jhordy Gavinchu
Gonzalo Gutiérrez Castillo
Gualberto Montiel
Inmutabilidad
¿Qué es inmutabilidad?
Algo que no puede ser cambiado después de su creación. - RAE
Redux no rendirazá la UI si no hay cambios entre el estado inicial y el estado final.
const updateAge = (userInfo) => { return { ...userInfo, age: userInfo.age + 1, }; } const userInfo = { name: 'Miguel', age: 23, email: 'miguel@platzi.com' } console.log('userInfo BEFORE: ', userInfo); console.log('userInfo AFTER: ', userInfo); console.log('updatedInfo: ', updateAge(userInfo));
Pero la inmutabilidad también tiene desventajas:
Inmutabilidad
Algo que no puede ser cambiado después de su creación
¿Por que es importante y en que se relaciona con Redux?
Mutabilidad en JS
const updateAge = (userInfo) => { userInfo.age = userInfo.age + 1 return userInfo } const userInfo = { name: 'juan', age: 25, email: 'jl@gmail.com' } console.log('Before userInfo: ', userInfo) // {name: 'juan', age: 25, email: 'jl@gmail.com'} const updateUserInfo = updateAge(userInfo) console.log('After userInfo: ',userInfo) // {name: 'juan', age: 26, email: 'jl@gmail.com'} console.log('updateUserInfo: ',updateUserInfo) // {name: 'juan', age: 26, email: 'jl@gmail.com'}
Inmutabilidad en JS
const updateAge = (userInfo) => { return Object.assign({}, userInfo, { age: userInfo.age + 1 }) } const userInfo = { name: 'juan', age: 25, email: 'jl@gmail.com' } console.log('Before userInfo: ', userInfo) // {name: 'juan', age: 25, email: 'jl@gmail.com'} const updateUserInfo = updateAge(userInfo) console.log('After userInfo: ',userInfo) // {name: 'juan', age: 25, email: 'jl@gmail.com'} console.log('updateUserInfo: ',updateUserInfo) // {name: 'juan', age: 26, email: 'jl@gmail.com'}
const updateAge = (userInfo) => { return { ...userInfo, age: userInfo.age + 1 } } const userInfo = { name: 'juan', age: 25, email: 'jl@gmail.com' } console.log('Before userInfo: ', userInfo) // {name: 'juan', age: 25, email: 'jl@gmail.com'} const updateUserInfo = updateAge(userInfo) console.log('After userInfo: ',userInfo) // {name: 'juan', age: 25, email: 'jl@gmail.com'} console.log('updateUserInfo: ',updateUserInfo) // {name: 'juan', age: 26, email: 'jl@gmail.com'}
Desventajas
Otro factor a tener en cuenta es que tanto el Spread Operator como Object.assing no funcionan con objetos que tienen otros objetos por dentro, lo que estaríamos copiando seria la referencia al objeto
const obj = {name: 'juan', age: 25, pleasures: { color: 'black' } } const obj2 = { ...obj } console.log(obj) // {name: 'juan', age: 25, pleasures: {color: 'black'}} console.log(obj2) // {name: 'juan', age: 25, pleasures: {color: 'black'}} console.log(obj.belongings == obj2.belongings) // true
si modificamos alguna propiedad del objeto numero uno, la del objeto numero dos quedaría igual, son objetos con clave y valor igual, pero son objetos diferentes, es decir, tienen una referencia distinta
const obj = {name: 'juan', age: 25, pleasures: { color: 'black' } } const obj2 = { ...obj } obj.name = 'oscar' console.log(obj) // {name: 'oscar', age: 25, pleasures: {color: 'black'}} console.log(obj2) // {name: 'juan', age: 25, pleasures: {color: 'black'}} console.log(obj.belongings == obj2.belongings) // true
pero si llegamos a modificar el color (propiedad del objeto dentro del objeto)
const obj = {name: 'juan', age: 25, pleasures: { color: 'black' } } const obj2 = { ...obj } obj.pleasures.color = 'white' console.log(obj) // {name: 'juan', age: 25, pleasures: {color: 'white'}} console.log(obj2) // {name: 'juan', age: 25, pleasures: {color: 'white'}} console.log(obj.belongings == obj2.belongings) // true
vemos que tanto en el objeto numero uno como en el objeto numero dos la propiedad color cambio, ambos objetos en su propiedad pleasures tienen como valor la referencia a un mismo objeto
🤔 Porque no se debe copiar un objeto como se copian los otros tipos de variables en JavaScript?
Comúnmente cuando quieres copiar el valor de una variable dentro de otra puedes hacer lo siguiente:
let myNumber = 5; let myOtherNumber = myNumber;
Ahora dentro de la variable "myOtherNumber" esta la copia del valor que esta en "myNumber" y puedes editar el valor sin afectar al original.
Qué pasa si intentamos copiar un objeto de la misma forma?
let myObject = { myNumber }; let myOtherObject = myObject;
En este caso al cambiar de alguna forma el objeto en "myOtherObject" también se verían reflejados esos cambios en el objeto que esta en "myObject".
Pero porque pasa eso????
Cuando inicializas una variable, esta señala a su valor en memoria y cuando creas una copia, la nueva variable copia lo que esta señalando la variable original.
Con los objetos es diferente:
Las variables con objetos no señalan a su valor, señalan hacía una referencia, por lo tanto al crear una copia de un objeto como se intento anteriormente, la nueva variable tendrá la referencia.
Al tener los dos objetos la misma referencia, editar uno de ellos es como editar al otro, porque al final los dos (por medio de sus referencias) señala al mismo objeto.
Es en esta caso donde para copiar realmente el valor de un objeto puedes usar Object.assign y el spread operator.
Ahora tenemos structuredClone una función nativa para copiar un objeto con todos sus niveles de profundidad
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
🧊 Inmutabilidad en JavaScript y Redux
La inmutabilidad significa que un valor no puede ser modificado después de su creación.
En el contexto de Redux esto es crítico, porque si el estado inicial y el estado retornado son exactamente iguales (misma referencia en memoria), la UI no se renderizará nuevamente.
En otras palabras:
> 🔁 Si mutas el objeto original, React/Redux no se entera del cambio.🧊 Si creas uno nuevo, sí puede detectar que hubo actualización.
🧰 Formas de lograr inmutabilidad en JavaScript
JavaScript ofrece varias maneras de crear nuevos objetos sin modificar el original:
Object.assign()...obj)Estas técnicas ayudan a generar una copia en lugar de mutar el objeto original.
🧪 Ejemplos (3 formas distintas de updateAge)
Partimos de este objeto:
const userInfo = { name: "Eddie", age: 22, email: "ed@gmail.com", }; console.log("userInfo BEFORE", userInfo); const updatedUserInfo = updateAge(userInfo); console.log("userInfo", userInfo); console.log("updatedUserInfo", updatedUserInfo);
1️⃣ Modificación directa (❌ rompe la inmutabilidad)
function updateAge(user) { user.age = user.age + 1; // Mutamos el objeto original return user; // Retornamos el mismo objeto modificado }
📌 Qué ocurre aquí:
userInfo en memoria.updatedUserInfo y userInfo quedan iguales.2️⃣ Usando Object.assign (✔️ copia sin mutar)
function updateAge(user) { return Object.assign({}, user, { age: user.age + 1 }); }
📌 Qué ocurre aquí:
age.userInfo permanece intacto.3️⃣ Usando spread operator (✔️ más moderno y recomendado)
function updateAge(user) { return { ...user, age: user.age + 1 }; }
📌 Qué ocurre aquí:
...user.age.⚠️ Desventajas de manejar inmutabilidad directamente con JavaScript
Aunque funciona, tiene algunos puntos negativos:
Además, si no comprendes bien cómo funciona el Garbage Collector, puedes terminar llenando memoria con objetos que nunca se liberan.
🛡️ Alternativa recomendada: ImmutableJS
Para evitar errores, mejorar la performance y asegurar la inmutabilidad, existe una librería que maneja todo esto por ti:
🧱 ImmutableJS
🔒 Inmutabilidad en JavaScript
💡 ¿Qué es?
La inmutabilidad significa que los datos no pueden cambiar después de ser creados. En lugar de modificar el original, siempre creamos una nueva copia con los cambios deseados.
🎯 Dato curioso: En JavaScript, los tipos primitivos (strings, números, booleanos) son naturalmente inmutables, pero los objetos y arrays son mutables por defecto.
javascript
// Los strings son inmutables let saludo = "Hola"; saludo += " Mundo"; // No modifica, crea un nuevo string
🎨 ¿Por qué es importante?
⚙️ Técnicas nativas en JavaScript
📦 Spread Operator (Moderno y recomendado)
javascript
const usuario = { nombre: "Ana", edad: 25 }; const usuarioActualizado = { ...usuario, edad: 26 }; // usuario sigue siendo { nombre: "Ana", edad: 25 }
📋 Object.assign (Clásico)
javascript
function actualizarEdad(usuario) { return Object.assign({}, usuario, { edad: usuario.edad + 1 }); }
❄️ Object.freeze() (Para evitar mutaciones)
javascript
const config = Object.freeze({ api: "" }); config.api = "otro"; // ¡No funciona! El objeto está congelado
⚠️ Limitación: Object.freeze() solo congela el primer nivel (shallow freeze), no objetos anidados.
🚧 Desafíos de la inmutabilidad
javascript
// Sin librería: verboso y propenso a errores const nuevoEstado = { ...estado, usuario: { ...estado.usuario, direccion: { ...estado.usuario.direccion, ciudad: "Nueva York" } } };
🛠️ Librerías especializadas
🌟 Immer.js (Recomendada - 2024)
Ganadora del premio "Breakthrough of the Year" en React Open Source (2019)
Immer usa el mecanismo copy-on-write: te permite escribir código que "parece" mutar el estado, pero internamente crea copias inmutables.
javascript
import { produce } from 'immer'; const estado = { tareas: [{ titulo: "Comprar leche", hecha: false }] }; const nuevoEstado = produce(estado, draft => { // ¡Puedes mutar el draft directamente! draft.tareas[0].hecha = true; draft.tareas.push({ titulo: "Pasear al perro", hecha: false }); }); // estado original no cambió ✨ console.log(estado.tareas[0].hecha); // false console.log(nuevoEstado.tareas[0].hecha); // true
✨ Ventajas de Immer:
⚠️ Consideraciones:
📚 Immutable.js (Para casos de alto rendimiento)
Usa estructuras de datos persistentes (TRIE structures y hash maps) para máxima eficiencia en colecciones grandes.
javascript
import { Map, List } from 'immutable'; const carrito = Map({ items: List([]), total: 0 }); const nuevoCarrito = carrito .updateIn(['items'], items => items.push(Map({ id: 1, precio: 999 }))) .update('total', total => total + 999);
⚡ Cuándo usar cada una:
🎯 1. Código más predecible y fácil de entender
Cuando usas datos inmutables, tienes la certeza de que una vez que se establece un valor, permanece constante freeCodeCamp. Esto elimina cambios inesperados y hace que tu código sea más fácil de razonar y debuggear.
Ejemplo práctico:
javascript
// ❌ Con mutabilidad (confuso) const usuario = { nombre: "Ana", edad: 25 }; procesarUsuario(usuario); console.log(usuario.edad); // ¿25? ¿26? No sabemos sin ver procesarUsuario() // ✅ Con inmutabilidad (claro) const usuario = { nombre: "Ana", edad: 25 }; const usuarioActualizado = procesarUsuario(usuario); console.log(usuario.edad); // Siempre 25 console.log(usuarioActualizado.edad); // Siempre 26
🧵 2. Seguridad en programación concurrente (Thread Safety)
En entornos multi-hilo, las estructuras de datos inmutables pueden compartirse libremente entre hilos sin necesidad de bloqueos o sincronización compleja freeCodeCamp. No hay riesgo de que dos procesos modifiquen los mismos datos al mismo tiempo.
Por qué importa: En aplicaciones modernas con muchas operaciones asíncronas (llamadas a APIs, timers, eventos), la inmutabilidad previene race conditions donde dos operaciones intentan modificar el mismo dato simultáneamente.
⚡ 3. Mejor rendimiento en React y frameworks modernos
La inmutabilidad permite comparaciones rápidas y económicas entre versiones del estado antes y después de los cambios Medium. Los componentes pueden detectar cambios comparando referencias de objetos en lugar de hacer comparaciones profundas.
Ejemplo:
javascript
// React puede detectar cambios instantáneamente const estadoAnterior = { items: [...] }; const estadoNuevo = { items: [...] }; // Comparación rápida por referencia if (estadoAnterior !== estadoNuevo) { // Re-renderizar (¡super rápido!) } // vs comparación profunda (lento) if (JSON.stringify(estadoAnterior) !== JSON.stringify(estadoNuevo)) { // Re-renderizar (mucho más lento) }
🐛 4. Debugging y tracking de cambios más sencillo
Mutar el estado oculta los cambios y crea efectos secundarios que pueden causar varios bugs, haciendo el debugging difícil Medium.
Con inmutabilidad tienes un "historial" completo de estados:
🧩 5. Programación funcional y composición
La inmutabilidad facilita paralelizar tu programa ya que no hay conflictos entre objetos DEV Community. Puedes combinar funciones sin preocuparte de que una modifique datos que otra necesita.
javascript
// Funciones puras componibles const agregarImpuesto = (precio) => ({ ...precio, total: precio.base * 1.19 }); const aplicarDescuento = (precio) => ({ ...precio, base: precio.base * 0.9 }); // Se pueden combinar sin efectos secundarios const precioFinal = agregarImpuesto(aplicarDescuento(precioInicial));
🔍 6. Caché y optimización de memoria
Los objetos inmutables se pueden cachear de forma segura, ya que una vez creados, pueden compartirse en diferentes partes del código sin preocuparse de modificaciones no deseadas Medium.
Ejemplo de structural sharing:
javascript
const lista1 = [1, 2, 3, 4, 5]; const lista2 = [...lista1, 6]; // Bibliotecas como Immer o Immutable.js // comparten la memoria de [1,2,3,4,5] // y solo crean nuevo espacio para el 6
📚 Resumen: ¿Cuándo importa más?
La inmutabilidad es especialmente crítica cuando:
Dato interesante: La inmutabilidad es tan crucial en el mundo reactivo de la programación que se puede contar como uno de sus fundamentos básicos freeCodeCamp. Sin ella, herramientas como Redux simplemente no funcionarían.
No estoy de acuerdo con que haya menos trazabilidad, por el contrario te genera mayor trazabilidad y control de tu código. Cuando los objetos son inmutables, cada cambio produce una nueva instancia del objeto, lo que facilita el seguimiento de cambios a lo largo del tiempo. Esto es particularmente útil en aplicaciones complejas donde el estado puede cambiar frecuentemente y de manera impredecible. Al poder identificar exactamente cuándo y cómo cambió el estado, con la tranquilidad de no haber dañado o modificado data u objetos originales.
Qué es inmutabilidad Algo que no puede ser cambiado después de su creación.
Que complejo de interpretar porque pocas veces se me ocurrio alterar un valor constante, pues por algo es constante 🤯
Tal vez tu confusion venga porque cuando asignamos un valor a una constantes, el tipo de dato queda amarrado a la constante y ya no se puede cambiar. Lo interesante es que cuando asignamos valores de tipos de datos primitivos (numericos o strings), la constante queda amarrada no solo al tipo de dato sino también al valor, pero cuando el tipo de dato es un objeto o un array, lo que queda amarrado a la constante, solo es el tipo de dato y su referencia, mas no el valor. Por eso es que se puede cambiar el valor de una constante que esta amarrada al tipo de dato array u object. No encuentro una manera mas facil de explicarlo
El concepto de Inmutabilidad es sencillo y poderoso. Un valor inmutable es algo que no puede ser cambiado.