JavaScript

JavaScript

Tutorial JavaScript: Inmutabilidad y programación funcional pura

JavaScript Inmutabilidad: Explora sus principios y beneficios para un código más seguro y mantenible.

Aprende JavaScript y certifícate

Principios de inmutabilidad: No modificación de datos después de su creación

La inmutabilidad es uno de los pilares fundamentales de la programación funcional en JavaScript. Este concepto, aparentemente simple, transforma radicalmente la forma en que diseñamos y estructuramos nuestro código. Un dato inmutable es aquel que, una vez creado, no puede ser modificado en ningún momento de su ciclo de vida.

¿Qué significa realmente la inmutabilidad?

En términos prácticos, la inmutabilidad implica que cuando necesitamos cambiar un valor, en lugar de modificar el original, creamos una nueva copia con las modificaciones deseadas. El valor original permanece intacto.

Veamos un ejemplo sencillo que ilustra la diferencia entre un enfoque mutable e inmutable:

// Enfoque mutable (modificando el original)
const addItemMutable = (cart, item) => {
  cart.push(item); // Modifica el array original
  return cart;
};

// Enfoque inmutable (creando una nueva copia)
const addItemImmutable = (cart, item) => {
  return [...cart, item]; // Crea un nuevo array
};

// Ejemplo de uso
const shoppingCart = ['apple', 'orange'];
const mutableCart = addItemMutable(shoppingCart, 'banana');
console.log(shoppingCart); // ['apple', 'orange', 'banana'] - ¡El original cambió!

const originalCart = ['apple', 'orange'];
const newCart = addItemImmutable(originalCart, 'banana');
console.log(originalCart); // ['apple', 'orange'] - El original se mantiene intacto
console.log(newCart); // ['apple', 'orange', 'banana'] - Tenemos una nueva versión

Beneficios de la inmutabilidad

La inmutabilidad no es solo una preferencia estilística, sino que ofrece ventajas tangibles:

  • Predictibilidad: El comportamiento del código es más predecible cuando los datos no cambian inesperadamente.
  • Depuración simplificada: Cuando un valor nunca cambia después de su creación, es más fácil rastrear su estado a lo largo del tiempo.
  • Concurrencia segura: Los datos inmutables son inherentemente seguros en entornos concurrentes, ya que no pueden ser modificados por múltiples procesos simultáneamente.
  • Facilita el testing: Las pruebas son más sencillas cuando podemos confiar en que los datos de entrada no serán alterados.
  • Historial de cambios: Cada modificación genera un nuevo estado, lo que facilita implementar funcionalidades como "deshacer" o mantener un historial.

Inmutabilidad con tipos primitivos y objetos

En JavaScript, los tipos primitivos (string, number, boolean, etc.) son inmutables por naturaleza:

let name = "Alice";
name.toUpperCase(); // Esto no modifica 'name', solo devuelve un nuevo valor
console.log(name); // Sigue siendo "Alice"

// Para cambiar el valor, debemos reasignar:
name = name.toUpperCase(); // Ahora name es "ALICE"

Sin embargo, los objetos y arrays son mutables por defecto, lo que significa que debemos aplicar técnicas específicas para trabajar con ellos de forma inmutable:

// Objeto mutable (forma incorrecta en programación funcional)
const user = { name: "Alice", age: 30 };
user.age = 31; // Mutación directa

// Enfoque inmutable (forma correcta)
const user = { name: "Alice", age: 30 };
const updatedUser = { ...user, age: 31 }; // Crea un nuevo objeto

Inmutabilidad en estructuras anidadas

Mantener la inmutabilidad en estructuras de datos complejas requiere especial atención:

const company = {
  name: "TechCorp",
  address: {
    city: "San Francisco",
    country: "USA"
  },
  employees: ["Alice", "Bob"]
};

// Actualizar una propiedad anidada de forma inmutable
const updatedCompany = {
  ...company,
  address: {
    ...company.address,
    city: "New York"
  }
};

// Añadir un empleado de forma inmutable
const companyWithNewEmployee = {
  ...company,
  employees: [...company.employees, "Charlie"]
};

Inmutabilidad y rendimiento

Una preocupación común sobre la inmutabilidad es su impacto en el rendimiento, ya que crear nuevas copias de datos grandes podría ser costoso. Sin embargo:

  • Las optimizaciones modernas de JavaScript (como la compartición estructural) mitigan muchos de estos problemas.
  • Existen bibliotecas especializadas como Immutable.js o Immer que implementan estructuras de datos inmutables eficientes.
  • El beneficio en mantenibilidad y reducción de errores suele superar el costo en rendimiento.
// Usando Immer (ejemplo conceptual)
import produce from 'immer';

const nextState = produce(currentState, draft => {
  draft.deeply.nested.property = newValue;
});

Aplicando inmutabilidad en el código diario

Para adoptar un estilo de programación inmutable, podemos seguir estas prácticas:

  • Preferir métodos no mutadores de arrays como map(), filter() y reduce() en lugar de push(), splice(), etc.
  • Utilizar el operador spread (...) para crear copias de objetos y arrays.
  • Evitar asignaciones directas a propiedades de objetos después de su creación.
  • Considerar el uso de Object.freeze() para prevenir modificaciones accidentales.
// Transformar un array de forma inmutable
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);

// Filtrar elementos de forma inmutable
const evenNumbers = numbers.filter(n => n % 2 === 0);

// Combinar operaciones de forma inmutable
const sum = numbers.reduce((total, n) => total + n, 0);

La inmutabilidad es un cambio de paradigma que puede resultar desafiante al principio, especialmente si estamos acostumbrados a la programación imperativa tradicional. Sin embargo, una vez adoptada, se convierte en una herramienta poderosa para escribir código más robusto, mantenible y menos propenso a errores.

Técnicas para operaciones inmutables: Object.freeze, spread y métodos no mutadores

Trabajar con inmutabilidad en JavaScript requiere conocer las herramientas y técnicas específicas que nos permiten manipular datos sin modificar los originales. Veamos las principales estrategias para implementar operaciones inmutables de manera efectiva.

Object.freeze(): Protección contra modificaciones

El método Object.freeze() es la forma más directa de hacer un objeto inmutable en JavaScript. Este método evita que se añadan, eliminen o modifiquen propiedades de un objeto.

const settings = Object.freeze({
  theme: "dark",
  notifications: true,
  fontSize: 16
});

// Intentar modificar el objeto congelado
settings.theme = "light"; // No produce error pero no tiene efecto
console.log(settings.theme); // Sigue siendo "dark"

// En modo estricto, intentar modificar lanza un error
"use strict";
settings.notifications = false; // TypeError: Cannot assign to read only property

Es importante entender las limitaciones de Object.freeze():

  • Solo congela el primer nivel del objeto (congelamiento superficial)
  • No afecta a objetos anidados dentro del objeto congelado

Para lograr un congelamiento profundo, necesitamos una implementación recursiva:

function deepFreeze(obj) {
  // Recuperar los nombres de propiedades definidas en obj
  const propNames = Object.getOwnPropertyNames(obj);
  
  // Congelar las propiedades antes de congelar el objeto
  propNames.forEach(name => {
    const prop = obj[name];
    
    // Congelar la propiedad si es un objeto
    if (typeof prop === 'object' && prop !== null) {
      deepFreeze(prop);
    }
  });
  
  // Congelar el objeto en sí
  return Object.freeze(obj);
}

const user = deepFreeze({
  name: "Alex",
  preferences: {
    theme: "dark",
    sidebar: "expanded"
  }
});

// Ahora ni siquiera las propiedades anidadas pueden modificarse
user.preferences.theme = "light"; // No tendrá efecto

Operador spread (...): Clonación y extensión

El operador spread es una de las herramientas más versátiles para trabajar con inmutabilidad, permitiendo crear copias de objetos y arrays con modificaciones específicas.

Para objetos:

const user = {
  id: 42,
  name: "Emma",
  role: "developer"
};

// Actualizar una propiedad de forma inmutable
const updatedUser = {
  ...user,
  role: "senior developer"
};

// Añadir nuevas propiedades
const userWithDetails = {
  ...user,
  department: "Engineering",
  location: "Remote"
};

console.log(user); // Original intacto
console.log(updatedUser); // Copia con role actualizado

Para arrays:

const fruits = ["apple", "orange", "banana"];

// Añadir elementos al final
const moreFruits = [...fruits, "grape", "kiwi"];

// Añadir elementos al principio
const evenMoreFruits = ["strawberry", ...fruits];

// Combinar arrays
const vegetables = ["carrot", "broccoli"];
const foodItems = [...fruits, ...vegetables];

// Eliminar un elemento (por índice)
const index = 1; // orange
const fruitsWithoutOrange = [
  ...fruits.slice(0, index),
  ...fruits.slice(index + 1)
];

console.log(fruits); // Original intacto: ["apple", "orange", "banana"]
console.log(fruitsWithoutOrange); // ["apple", "banana"]

Métodos no mutadores de arrays

JavaScript proporciona varios métodos de array que no modifican el original, sino que devuelven un nuevo array con los cambios aplicados:

const numbers = [1, 2, 3, 4, 5];

// map(): transforma cada elemento
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10]

// filter(): selecciona elementos según una condición
const evenNumbers = numbers.filter(n => n % 2 === 0);
// [2, 4]

// reduce(): acumula valores
const sum = numbers.reduce((total, n) => total + n, 0);
// 15

// concat(): combina arrays
const moreNumbers = numbers.concat([6, 7, 8]);
// [1, 2, 3, 4, 5, 6, 7, 8]

// slice(): extrae una porción del array
const subset = numbers.slice(1, 4);
// [2, 3, 4]

Estos métodos contrastan con los métodos mutadores como push(), pop(), shift(), unshift(), splice(), sort() y reverse(), que modifican el array original.

Comparativa: Operaciones mutables vs. inmutables

Veamos cómo transformar operaciones mutables comunes en sus equivalentes inmutables:

  • 1. Añadir elementos a un array:
// Mutable
const addMutable = (array, item) => {
  array.push(item);
  return array;
};

// Inmutable
const addImmutable = (array, item) => {
  return [...array, item];
};
  • 2. Eliminar elementos de un array:
// Mutable
const removeMutable = (array, index) => {
  array.splice(index, 1);
  return array;
};

// Inmutable
const removeImmutable = (array, index) => {
  return [
    ...array.slice(0, index),
    ...array.slice(index + 1)
  ];
};
  • 3. Actualizar propiedades de un objeto:
// Mutable
const updateMutable = (object, key, value) => {
  object[key] = value;
  return object;
};

// Inmutable
const updateImmutable = (object, key, value) => {
  return { ...object, [key]: value };
};
  • 4. Ordenar un array:
// Mutable
const sortMutable = (array) => {
  return array.sort();
};

// Inmutable
const sortImmutable = (array) => {
  return [...array].sort();
};

Técnicas para estructuras de datos complejas

Cuando trabajamos con estructuras anidadas, mantener la inmutabilidad se vuelve más desafiante:

const project = {
  id: "proj-123",
  title: "Website Redesign",
  client: {
    id: "client-456",
    name: "Acme Corp",
    contact: {
      email: "contact@acme.com",
      phone: "555-1234"
    }
  },
  tasks: [
    { id: 1, description: "Wireframes", completed: true },
    { id: 2, description: "Design", completed: false }
  ]
};

// Actualizar un valor profundamente anidado
const updatedProject = {
  ...project,
  client: {
    ...project.client,
    contact: {
      ...project.client.contact,
      email: "new-contact@acme.com"
    }
  }
};

// Marcar una tarea como completada
const taskId = 2;
const updatedTasks = {
  ...project,
  tasks: project.tasks.map(task => 
    task.id === taskId 
      ? { ...task, completed: true }
      : task
  )
};

Bibliotecas para inmutabilidad

Para proyectos más complejos, existen bibliotecas que facilitan el trabajo con datos inmutables:

  • Immer: Permite escribir código que parece mutable pero produce resultados inmutables.
import produce from 'immer';

const nextState = produce(project, draft => {
  // Esto parece código mutable, pero Immer lo convierte en inmutable
  draft.client.contact.email = "new-contact@acme.com";
  draft.tasks[1].completed = true;
});
  • Immutable.js: Proporciona estructuras de datos inmutables optimizadas.
import { Map, List } from 'immutable';

const immutableProject = Map({
  id: "proj-123",
  tasks: List([
    Map({ id: 1, completed: false }),
    Map({ id: 2, completed: false })
  ])
});

const updated = immutableProject.setIn(['tasks', 1, 'completed'], true);

Patrones prácticos para inmutabilidad

Algunos patrones útiles al trabajar con inmutabilidad:

  • Funciones de actualización: Crear funciones específicas para actualizar partes de un estado.
// Función para actualizar un elemento en un array por id
const updateItemById = (array, id, updates) => {
  return array.map(item => 
    item.id === id ? { ...item, ...updates } : item
  );
};

// Uso
const updatedTasks = updateItemById(project.tasks, 2, { completed: true });
  • Selectores: Funciones que extraen datos específicos sin modificar la fuente.
// Selector para obtener tareas completadas
const getCompletedTasks = project => 
  project.tasks.filter(task => task.completed);

// Uso
const completedTasks = getCompletedTasks(project);

La inmutabilidad es un cambio de mentalidad que requiere práctica, pero estas técnicas proporcionan las herramientas necesarias para implementarla de manera efectiva en JavaScript, llevándonos un paso más cerca de la programación funcional pura.

Funciones puras: Determinismo, ausencia de efectos secundarios y transparencia referencial

Las funciones puras constituyen otro pilar fundamental de la programación funcional en JavaScript. Una función pura es aquella que cumple con dos características esenciales: siempre produce el mismo resultado para los mismos argumentos de entrada (determinismo) y no causa efectos secundarios observables fuera de su ámbito.

Determinismo: mismas entradas, mismas salidas

El determinismo es la propiedad por la cual una función, al recibir los mismos parámetros de entrada, siempre devuelve exactamente el mismo resultado, sin importar cuándo o cuántas veces se ejecute. Esta característica hace que el comportamiento de la función sea completamente predecible.

// Función pura: determinista
const sum = (a, b) => a + b;

console.log(sum(5, 3)); // Siempre devuelve 8
console.log(sum(5, 3)); // Siempre devuelve 8, sin importar cuántas veces la llamemos

Comparemos con una función no determinista:

// Función impura: no determinista
const randomSum = (a) => a + Math.random();

console.log(randomSum(5)); // Podría devolver 5.12345...
console.log(randomSum(5)); // Podría devolver 5.67890... (diferente resultado)

Ausencia de efectos secundarios

Un efecto secundario ocurre cuando una función modifica algún estado fuera de su ámbito local o tiene una interacción observable con el mundo exterior más allá de retornar un valor. Las funciones puras están libres de estos efectos.

Ejemplos de efectos secundarios incluyen:

  • Modificar variables globales o parámetros recibidos
  • Realizar operaciones de E/S (escribir en consola, modificar el DOM, hacer peticiones HTTP)
  • Modificar el sistema de archivos
  • Lanzar excepciones o errores
  • Llamar a otras funciones que producen efectos secundarios
// Función impura: tiene efectos secundarios
let total = 0;

const addToTotal = (value) => {
  total += value; // Modifica una variable externa
  return total;
};

// Función pura: sin efectos secundarios
const add = (a, b) => a + b;

Veamos otro ejemplo más elaborado:

// Función impura: modifica el DOM (efecto secundario)
const updateHeader = (text) => {
  document.getElementById('header').textContent = text;
};

// Versión más pura: devuelve lo que se debería hacer, sin hacerlo directamente
const createHeaderUpdate = (text) => {
  return {
    type: 'UPDATE_HEADER',
    payload: { id: 'header', textContent: text }
  };
};

Transparencia referencial

La transparencia referencial significa que una expresión puede ser reemplazada por su valor resultante sin cambiar el comportamiento del programa. Es una consecuencia directa del determinismo y la ausencia de efectos secundarios.

// Función con transparencia referencial
const double = (x) => x * 2;

// En cualquier parte del código, podemos reemplazar double(5) por 10
const result = double(5) + double(5);
// Es equivalente a:
const sameResult = 10 + 10;

Esta propiedad facilita enormemente el razonamiento sobre el código, ya que podemos analizar cada parte de forma aislada.

Beneficios de las funciones puras

Las funciones puras ofrecen numerosas ventajas:

  • Facilidad de prueba: Al depender solo de sus entradas y no tener efectos secundarios, son extremadamente fáciles de probar.
  • Memoización: Podemos almacenar en caché los resultados para entradas específicas, mejorando el rendimiento.
  • Paralelización: Al no depender de estados compartidos, pueden ejecutarse en paralelo sin riesgos.
  • Razonamiento local: Podemos entender y razonar sobre la función examinando solo su implementación.
  • Composición: Se pueden combinar fácilmente para crear funciones más complejas.
// Ejemplo de memoización con funciones puras
const memoize = (fn) => {
  const cache = {};
  
  return (...args) => {
    const key = JSON.stringify(args);
    if (key in cache) {
      return cache[key];
    }
    
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
};

// Función pura costosa
const fibonacci = (n) => {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

// Versión memoizada
const memoFibonacci = memoize(fibonacci);

console.time('Sin memoización');
fibonacci(40);
console.timeEnd('Sin memoización');

console.time('Con memoización');
memoFibonacci(40);
console.timeEnd('Con memoización');

Identificando funciones impuras

Para reconocer funciones impuras, busca estos indicadores:

  • Uso de variables globales o externas a la función
  • Modificación de parámetros recibidos
  • Llamadas a APIs del navegador (DOM, localStorage, fetch)
  • Operaciones de E/S (console.log, alert)
  • Generación de valores aleatorios o dependientes del tiempo
// Ejemplos de funciones impuras
const impureFunction1 = (arr) => {
  arr.push(1); // Modifica el array original
  return arr;
};

const impureFunction2 = (x) => {
  console.log(x); // Efecto secundario: escribe en consola
  return x * 2;
};

const impureFunction3 = () => {
  return new Date().toISOString(); // Depende del tiempo (no determinista)
};

Transformando funciones impuras en puras

Muchas funciones impuras pueden refactorizarse para hacerlas puras:

// Impura: modifica el array original
const addItem = (cart, item) => {
  cart.push(item);
  return cart;
};

// Pura: crea un nuevo array
const addItemPure = (cart, item) => {
  return [...cart, item];
};

// Impura: usa y modifica estado externo
let counter = 0;
const incrementCounter = () => {
  counter++;
  return counter;
};

// Pura: recibe el estado y devuelve el nuevo valor
const incrementPure = (count) => count + 1;

Efectos secundarios en el mundo real

En aplicaciones reales, los efectos secundarios son inevitables (necesitamos mostrar datos en pantalla, hacer peticiones HTTP, etc.). La clave está en:

  1. Aislar los efectos secundarios en partes específicas del código
  2. Mantener la mayor parte de la lógica en funciones puras
  3. Empujar los efectos secundarios hacia los bordes de la aplicación
// Arquitectura con efectos secundarios aislados
const fetchUserData = async (userId) => {
  // Efecto secundario aislado: petición HTTP
  const response = await fetch(`/api/users/${userId}`);
  const data = await response.json();
  return data;
};

// Función pura: procesa los datos
const getUserDisplayName = (user) => {
  return user.firstName && user.lastName 
    ? `${user.firstName} ${user.lastName}`
    : user.username;
};

// Componente que combina ambos
const UserProfile = async ({ userId }) => {
  // Efecto secundario en el borde de la aplicación
  const userData = await fetchUserData(userId);
  
  // Lógica pura en el centro
  const displayName = getUserDisplayName(userData);
  
  // Efecto secundario en el borde (renderizado)
  return `<div class="profile">${displayName}</div>`;
};

Composición de funciones puras

Una de las grandes ventajas de las funciones puras es que se pueden componer fácilmente para crear funcionalidades más complejas:

// Funciones puras simples
const double = x => x * 2;
const increment = x => x + 1;
const square = x => x * x;

// Composición manual
const transformManual = x => square(increment(double(x)));

// Función helper para composición
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

// Composición con helper
const transform = compose(square, increment, double);

console.log(transform(3)); // 49 (equivalente a square(increment(double(3))))

Programación declarativaz con funciones puras

Las funciones puras facilitan un estilo de programación declarativo (especificar qué hacer, no cómo hacerlo):

// Datos de ejemplo
const products = [
  { id: 1, name: "Laptop", price: 1200, category: "Electronics" },
  { id: 2, name: "Headphones", price: 100, category: "Electronics" },
  { id: 3, name: "Coffee Mug", price: 15, category: "Kitchen" },
  { id: 4, name: "Notebook", price: 10, category: "Office" }
];

// Funciones puras para transformar datos
const filterByCategory = (products, category) => 
  products.filter(product => product.category === category);

const applyDiscount = (products, percentage) => 
  products.map(product => ({
    ...product,
    price: product.price * (1 - percentage / 100)
  }));

const sortByPrice = products => 
  [...products].sort((a, b) => a.price - b.price);

const calculateTotal = products => 
  products.reduce((sum, product) => sum + product.price, 0);

// Composición de operaciones
const discountedElectronics = compose(
  products => calculateTotal(products),
  products => sortByPrice(products),
  products => applyDiscount(products, 10),
  products => filterByCategory(products, "Electronics")
)(products);

La programación con funciones puras nos permite construir sistemas más robustos, predecibles y mantenibles. Aunque requiere un cambio de mentalidad, especialmente para desarrolladores acostumbrados a estilos imperativos, los beneficios en términos de calidad de código y facilidad de razonamiento son sustanciales.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende JavaScript online

Ejercicios de esta lección Inmutabilidad y programación funcional pura

Evalúa tus conocimientos de esta lección Inmutabilidad y programación funcional pura con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Funciones flecha

JavaScript
Puzzle

Polimorfismo

JavaScript
Test

Array

JavaScript
Código

Transformación con map()

JavaScript
Test

Gestor de tareas con JavaScript

JavaScript
Proyecto

Manipulación DOM

JavaScript
Test

Funciones

JavaScript
Test

Funciones flecha

JavaScript
Código

Async / Await

JavaScript
Código

Creación y uso de variables

JavaScript
Test

Excepciones

JavaScript
Puzzle

Promises

JavaScript
Código

Funciones cierre (closure)

JavaScript
Test

Herencia

JavaScript
Puzzle

Herencia

JavaScript
Test

Estructuras de control

JavaScript
Código

Selección de elementos DOM

JavaScript
Test

Modificación de elementos DOM

JavaScript
Test

Filtrado con filter() y find()

JavaScript
Test

Funciones cierre (closure)

JavaScript
Puzzle

Funciones

JavaScript
Puzzle

Mapas con Map

JavaScript
Test

Reducción con reduce()

JavaScript
Test

Callbacks

JavaScript
Puzzle

Manipulación DOM

JavaScript
Puzzle

Promises

JavaScript
Test

Async / Await

JavaScript
Test

Eventos del DOM

JavaScript
Puzzle

Async / Await

JavaScript
Puzzle

Promises

JavaScript
Puzzle

Filtrado con filter() y find()

JavaScript
Código

Callbacks

JavaScript
Test

Creación de clases y objetos Restaurante

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Puzzle

Reducción con reduce()

JavaScript
Puzzle

Conjuntos con Set

JavaScript
Puzzle

Herencia de clases

JavaScript
Código

Eventos del DOM

JavaScript
Test

Clases y objetos

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Puzzle

Mapas con Map

JavaScript
Puzzle

Introducción a JavaScript

JavaScript
Test

Funciones

JavaScript
Código

Tipos de datos

JavaScript
Test

Clases y objetos

JavaScript
Test

Array

JavaScript
Test

Conjuntos con Set

JavaScript
Test

Array

JavaScript
Puzzle

Encapsulación

JavaScript
Puzzle

Clases y objetos

JavaScript
Código

Uso de operadores

JavaScript
Puzzle

Uso de operadores

JavaScript
Test

Estructuras de control

JavaScript
Test

Excepciones

JavaScript
Test

Transformación con map()

JavaScript
Puzzle

Funciones flecha

JavaScript
Test

Selección de elementos DOM

JavaScript
Puzzle

Encapsulación

JavaScript
Test

Mapas con Map

JavaScript
Código

Creación y uso de variables

JavaScript
Puzzle

Polimorfismo

JavaScript
Puzzle

Tipos de datos

JavaScript
Puzzle

Estructuras de control

JavaScript
Puzzle

Todas las lecciones de JavaScript

Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a JavaScript y certifícate

Certificados de superación de JavaScript

Supera todos los ejercicios de programación del curso de JavaScript y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender el concepto de inmutabilidad y cómo se aplica en JavaScript.
  • Identificar las ventajas de utilizar inmutabilidad en el desarrollo de software.
  • Implementar técnicas como Object.freeze, spread operator y métodos no mutadores.
  • Diferenciar entre funciones puras e impuras y sus efectos en el código.
  • Adoptar buenas prácticas para trabajar con estructuras de datos inmutables.
  • Aprovechar bibliotecas especializadas para mejorar la inmutabilidad.