Desestructuración y Spread

Extrae y combina datos de objetos y arrays con claridad usando desestructuración, rest y spread.

La desestructuración permite extraer valores de objetos y arrays en variables con una sintaxis compacta. El operador spread (...) los complementa para copiar y combinar estructuras. Juntos son ubicuos en JavaScript moderno.


Desestructuración de objetos

const usuario = { nombre: 'Ana', edad: 28, ciudad: 'Madrid' };

// Sin desestructuración
const nombre = usuario.nombre;
const edad = usuario.edad;

// Con desestructuración
const { nombre, edad } = usuario;
console.log(nombre);  // 'Ana'
console.log(edad);    // 28

// Renombrar al extraer
const { nombre: nombreUsuario, ciudad: localidad } = usuario;
console.log(nombreUsuario);  // 'Ana'
console.log(localidad);      // 'Madrid'

// Valor por defecto si la propiedad no existe
const { nombre, rol = 'lector' } = usuario;
console.log(rol);  // 'lector' — la propiedad no existía en el objeto

Desestructuración de arrays

const colores = ['rojo', 'verde', 'azul'];

const [primero, segundo] = colores;
console.log(primero);   // 'rojo'
console.log(segundo);   // 'verde'

// Saltar elementos
const [, , tercero] = colores;
console.log(tercero);  // 'azul'

// Intercambiar variables sin temporal
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b);  // 2 1

Rest en desestructuración

El operador ...rest recoge lo que no se extrajo. Solo puede ir al final:

// En objetos
const { nombre, ...resto } = usuario;
console.log(nombre);  // 'Ana'
console.log(resto);   // { edad: 28, ciudad: 'Madrid' }

// En arrays
const [primero, ...losOtros] = [1, 2, 3, 4, 5];
console.log(primero);    // 1
console.log(losOtros);   // [2, 3, 4, 5]

Desestructuración anidada

const config = {
  servidor: {
    host: 'localhost',
    puerto: 3000,
  },
  bd: {
    nombre: 'miapp',
    usuario: 'admin',
  },
};

// Extraer propiedades profundas
const { servidor: { host, puerto }, bd: { nombre: bdNombre } } = config;
console.log(host);      // 'localhost'
console.log(puerto);    // 3000
console.log(bdNombre);  // 'miapp'

Desestructuración en parámetros de función

Es el uso más frecuente en frontend moderno:

// Sin desestructuración
function mostrarUsuario(usuario) {
  console.log(usuario.nombre, usuario.email);
}

// Con desestructuración en el parámetro
function mostrarUsuario({ nombre, email }) {
  console.log(nombre, email);
}

// Con valor por defecto en los parámetros
function crearElemento({ tag = 'div', clase = '', texto = '' } = {}) {
  const el = document.createElement(tag);
  el.className = clase;
  el.textContent = texto;
  return el;
}

// = {} al final hace que la función funcione sin argumento
crearElemento();                              // div vacío
crearElemento({ tag: 'p', texto: 'Hola' });  // <p>Hola</p>

Spread en objetos

Copia y combina propiedades:

const base = { color: 'rojo', tamaño: 'M' };
const extra = { precio: 10, stock: 5 };

// Combinar objetos
const producto = { ...base, ...extra };
// { color: 'rojo', tamaño: 'M', precio: 10, stock: 5 }

// Copiar con modificación (la propiedad más a la derecha gana)
const actualizado = { ...base, color: 'azul' };
// { color: 'azul', tamaño: 'M' }

// Actualizar estado de forma inmutable (patrón React/Redux)
const estado = { usuario: 'Ana', paginaActual: 1, cargando: false };
const nuevoEstado = { ...estado, paginaActual: 2 };

El spread es superficial (shallow copy). Las propiedades anidadas siguen siendo referencias compartidas.

const obj = { a: 1, nested: { b: 2 } };
const copia = { ...obj };

copia.a = 99;           // no afecta al original
copia.nested.b = 99;    // ← SÍ afecta al original (referencia compartida)

Spread en arrays

const nums = [1, 2, 3];

// Copiar un array
const copia = [...nums];

// Combinar arrays
const mas = [...nums, 4, 5, 6];
// [1, 2, 3, 4, 5, 6]

const combinado = [...[1, 2], ...[3, 4], 5];
// [1, 2, 3, 4, 5]

// Pasar array como argumentos
const maxValor = Math.max(...nums);  // equivale a Math.max(1, 2, 3)

Desestructuración con iterables

La desestructuración de array funciona con cualquier iterable: strings, Maps, Sets, resultados de generators:

const [primera, segunda] = 'Hola';
console.log(primera);   // 'H'
console.log(segunda);   // 'o'

const [clave, valor] = new Map([['nombre', 'Ana']]).entries().next().value;

// Muy útil con Object.entries
const precios = { manzana: 1.2, pera: 0.8 };
for (const [fruta, precio] of Object.entries(precios)) {
  console.log(`${fruta}: ${precio}€`);
}

En la siguiente lección entramos en uno de los conceptos más profundos de JavaScript: closures y scope.