Destructuring avanzado en JavaScript: renombrar, defaults, anidado, rest y en parámetros

La desestructuración en JavaScript va mucho más allá de extraer valores de arrays u objetos en variables simples. Las técnicas avanzadas —renombrar variables, valores por defecto, desestructuración anidada, el operador rest y los computed property names— permiten escribir código más conciso y expresivo en una gran variedad de situaciones.

Renombrar variables al desestructurar

Cuando el nombre de la propiedad del objeto no es un buen nombre para la variable local, se puede renombrar en la misma desestructuración con la sintaxis propiedad: nuevoNombre:

const respuestaAPI = {
  user_name: 'ana_dev',
  user_id: 42,
  created_at: '2024-01-15',
  is_active: true,
};

// Desestructurar y renombrar en una sola línea
const {
  user_name: nombreUsuario,
  user_id: id,
  created_at: fechaCreacion,
  is_active: activo,
} = respuestaAPI;

console.log(nombreUsuario, id); // 'ana_dev', 42

// Útil al trabajar con APIs snake_case desde código camelCase

Valores por defecto

Los valores por defecto se asignan solo cuando la propiedad es undefined (no cuando es null):

const config = {
  host: 'localhost',
  timeout: null,  // null explícito
  // puerto: no existe
};

const {
  host,
  puerto = 3000,      // default: config.puerto es undefined
  timeout = 5000,     // NO aplica: config.timeout es null, no undefined
  debug = false,
} = config;

console.log(host);    // 'localhost'
console.log(puerto);  // 3000 (se usó el default)
console.log(timeout); // null (null != undefined, no se usa el default)
console.log(debug);   // false (se usó el default)

// Combinado con renombrado
const { user_name: nombre = 'Anónimo', role: rol = 'visitante' } = {};
console.log(nombre, rol); // 'Anónimo', 'visitante'

Desestructuración anidada

Se puede desestructurar en varios niveles de profundidad en una sola expresión. Útil para extraer datos de respuestas JSON profundamente anidadas:

const respuesta = {
  status: 200,
  data: {
    usuario: {
      id: 42,
      nombre: 'Ana',
      direccion: {
        ciudad: 'Madrid',
        cp: '28001',
      },
    },
    meta: {
      pagina: 1,
      total: 100,
    },
  },
};

const {
  status,
  data: {
    usuario: {
      nombre,
      direccion: { ciudad, cp },
    },
    meta: { pagina, total },
  },
} = respuesta;

console.log(nombre, ciudad, total); // 'Ana', 'Madrid', 100

// OJO: si un nivel intermedio es undefined, lanza TypeError
// Usar optional chaining o valores por defecto en el nivel intermedio:
const { data: { usuario: { mascota: { tipo } = {} } = {} } = {} } = respuesta;
console.log(tipo); // undefined — sin error

Operador rest en desestructuración

El operador rest (...) recoge el "resto" de propiedades o elementos no desestructurados explícitamente:

// Rest en objetos
const { nombre, email, ...restoUsuario } = {
  nombre: 'Ana',
  email: '[email protected]',
  password: 'hashed_pw',
  token: 'abc123',
  ultimoAcceso: '2024-03-15',
};

console.log(nombre);        // 'Ana'
console.log(restoUsuario);  // { password: 'hashed_pw', token: 'abc123', ultimoAcceso: '2024-03-15' }

// Muy útil para excluir campos sensibles antes de enviar:
const { password, token, ...usuarioPublico } = usuario;
enviarAlCliente(usuarioPublico); // Sin contraseña ni token

// Rest en arrays
const [primero, segundo, ...restantes] = [1, 2, 3, 4, 5, 6];
console.log(primero);    // 1
console.log(segundo);    // 2
console.log(restantes);  // [3, 4, 5, 6]

Swap de variables con desestructuración de array

let a = 'primero';
let b = 'segundo';

// Sin desestructuración necesitas una variable temporal
// let temp = a; a = b; b = temp;

// Con desestructuración: una línea
[a, b] = [b, a];
console.log(a, b); // 'segundo', 'primero'

// Útil en algoritmos de ordenación o permutaciones
function burbuja(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

Ignorar posiciones en arrays

// Ignorar elementos con comas vacías
const [, segundo, , cuarto] = [1, 2, 3, 4, 5];
console.log(segundo, cuarto); // 2, 4

// Útil con el resultado de match/exec en regex
const fechaStr = '2024-03-15';
const [, anio, mes, dia] = fechaStr.match(/(d{4})-(d{2})-(d{2})/);
console.log(anio, mes, dia); // '2024', '03', '15'

// O con Object.entries cuando solo necesitas valores
for (const [, valor] of Object.entries(configuracion)) {
  console.log(valor);
}

Computed property names

const campo = 'nombre';
const { [campo]: valor } = { nombre: 'Ana', email: '[email protected]' };
console.log(valor); // 'Ana'

// Útil en funciones genéricas que desestructuran por nombre dinámico
function obtenerCampo(obj, nombreCampo) {
  const { [nombreCampo]: resultado } = obj;
  return resultado;
}

console.log(obtenerCampo({ a: 1, b: 2 }, 'b')); // 2

Desestructuración en parámetros de función

// Objeto de opciones con defaults inline
function crearConexion({
  host = 'localhost',
  puerto = 5432,
  ssl = false,
  timeout = 5000,
  usuario = 'postgres',
} = {}) {
  console.log(`Conectando a ${host}:${puerto} (SSL: ${ssl})`);
}

crearConexion({ host: 'db.ejemplo.com', ssl: true });
crearConexion(); // Usa todos los defaults gracias al = {}

// En callbacks de map/filter con arrays de objetos
const productos = [
  { id: 1, nombre: 'Teclado', precio: 89, activo: true },
  { id: 2, nombre: 'Ratón', precio: 29, activo: false },
];

const nombres = productos
  .filter(({ activo }) => activo)
  .map(({ nombre, precio }) => `${nombre}: ${precio}€`);

console.log(nombres); // ['Teclado: 89€']

La desestructuración avanzada de JavaScript es una herramienta que, usada correctamente, hace el código más declarativo y expresivo. La clave es no abusar de la anidación profunda —más de dos o tres niveles empieza a dificultar la lectura— y recordar que los valores por defecto solo aplican a undefined, nunca a null.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP