learning-front

Nivel 3 · JavaScript moderno y asíncrono

Destructuring a fondo

Destructuring avanzado: anidamiento, parámetros de función, intercambio de variables y patrones reales con for...of y Object.entries. Sobre la base de lo que ya practicaste en el Nivel 2.

En el capítulo de arrays y objetos del Nivel 2 aprendiste la base: const { nombre, rol } = heroe desempaqueta propiedades de un objeto, y const [primero, segundo] = alineacion hace lo mismo con un array por posición. Si necesitas refrescar lo básico, vuelve a ese capítulo.

Aquí vamos a los patrones que de verdad se usan a diario en código de empresa: bajar un nivel (anidado), destruturar en la firma de una función, intercambiar variables en una línea, y los patrones con for...of y Object.entries. Con el dataset de siempre: héroes del Overwatch Team Builder.

Los héroes tienen nombre, rol, partidas, victorias y un objeto anidado stats (con rango y mvp). El objeto equipo agrupa metadatos y una alineacion (array de nombres).

Recordatorio compacto#

Si necesitas el destructuring básico de un vistazo antes de empezar:

javascript
// Partimos de un héroe de ejemplo.
const heroe = { nombre: "Tracer", rol: "Daño", partidas: 120, victorias: 78 };
const alineacion = ["Mercy", "Reinhardt", "Tracer"];

// Objeto: una variable por clave (el orden no importa).
// equivale a const nombre = heroe.nombre; const rol = heroe.rol;
const { nombre, rol } = heroe;
// Tracer (Daño)
console.log(nombre + " (" + rol + ")");

// Renombrar: la clave 'nombre' va a la variable 'nombreHeroe'.
// la variable 'nombre' NO existe; usamos 'nombreHeroe'
const { nombre: nombreHeroe } = heroe;
// Tracer
console.log(nombreHeroe);

// Valor por defecto: si la clave falta, se usa el valor que pongas.
// rango no existe en heroe → usa 'Sin clasificar'
const { rango = "Sin clasificar" } = heroe;
// Sin clasificar
console.log(rango);

// Array: por posición (el orden sí importa).
// primero = índice 0, segundo = índice 1
const [primero, segundo] = alineacion;
// Mercy
console.log(primero);

// Saltar posición: coma sola para ignorar el índice 0.
// ignora el índice 0, coge el 1
const [, suplente] = alineacion;
// Reinhardt
console.log(suplente);

Con eso claro, entramos en lo nuevo.

Destructuring anidado: bajar un nivel#

Cuando el dato vive dentro de otro objeto, puedes desempaquetar en profundidad replicando la forma del objeto a la izquierda del =.

javascript
// stats es un objeto dentro del héroe.
const heroe = {
  nombre: "Tracer",
  stats: { rango: "Diamante", mvp: 12 },
};

// Baja un nivel: de heroe saca stats, y de stats saca rango y mvp.
// La forma de la izquierda imita la del objeto.
const {
  nombre,
  stats: { rango, mvp },
} = heroe;
// nombre → 'Tracer'   rango → 'Diamante'   mvp → 12
// OJO: 'stats' NO queda como variable; solo es el camino para llegar a rango y mvp.

// Tracer — Diamante (12 MVP)
console.log(nombre + "" + rango + " (" + mvp + " MVP)");

Si el objeto anidado podría no existir, combina el anidado con un valor por defecto del objeto entero, para no reventar:

javascript
// sin stats
const heroe = { nombre: "Genji" };

// El = {} de stats evita el error si stats falta; el = 'Sin clasificar' cubre rango.
const { stats: { rango = "Sin clasificar" } = {} } = heroe;
// Sin clasificar  (no peta aunque no haya stats)
console.log(rango);

Destructuring en los parámetros de una función#

El uso que más vas a ver. Si una función recibe un objeto, puedes destructurarlo en la propia firma: la función declara qué campos usa y su cuerpo queda limpio.

javascript
// La función recibe el héroe entero, pero la firma solo nombra lo que usa.
// Dentro no hay un solo heroe.: trabajamos con nombre, rol, victorias, partidas.
function fichaHeroe({ nombre, rol, victorias, partidas }) {
  // winrate en %
  const winrate = ((victorias / partidas) * 100).toFixed(1);
  return nombre + " (" + rol + ") — " + winrate + "%";
}

const tracer = { nombre: "Tracer", rol: "Daño", partidas: 120, victorias: 78 };
// Tracer (Daño) — 65.0%
console.log(fichaHeroe(tracer));

Esto es exactamente lo que verás en React: function Ficha({ nombre, rol }) { ... }. Lo que allí llaman “desestructurar las props” es esto mismo. Aprenderlo ahora, con JavaScript a secas, es quitarte ese obstáculo antes de tiempo.

Intercambio de variables sin temporal#

Un truco clásico: intercambiar el valor de dos variables normalmente necesita una tercera variable de paso. Con destructuring, se hace en una línea:

javascript
// queremos que capitan sea 'Tracer' y suplente sea 'Mercy'
let capitan  = 'Mercy';
let suplente = 'Tracer';

// Intercambio con destructuring: el array de la derecha evalúa ANTES de asignar.
// [suplente, capitan] crea un array con los valores actuales: ['Tracer', 'Mercy']
// luego los asigna a capitan y suplente por posición
[capitan, suplente] = [suplente, capitan];
// capitan → 'Tracer'   suplente → 'Mercy'
console.log('Nuevo capitán: ' + capitan);
console.log('Nuevo suplente: ' + suplente);

Sin destructuring haría falta const tmp = capitan; capitan = suplente; suplente = tmp;. Son tres líneas en vez de una, y la variable tmp no aporta nada al significado.

Destructuring con for...of y Object.entries#

Ya conoces el bucle for...of y Object.entries del capítulo de arrays y objetos. Combinados con destructuring quedan mucho más limpios:

javascript
// array de héroes de ejemplo
const heroes = [
  { nombre: 'Tracer',    rol: 'Daño',   partidas: 120, victorias: 78 },
  { nombre: 'Reinhardt', rol: 'Tanque', partidas: 90,  victorias: 51 },
  { nombre: 'Mercy',     rol: 'Apoyo',  partidas: 200, victorias: 130 },
];

// Destructuring directamente en la cabecera del for...of.
// En cada iteración, heroe se desempaqueta: nombre y victorias están listos.
for (const { nombre, victorias, partidas } of heroes) {
  // no hace falta heroe.nombre, heroe.victorias, etc.
  console.log(nombre + ': ' + victorias + '/' + partidas);
}

Con Object.entries y un objeto de estadísticas:

javascript
// objeto de estadísticas del equipo
const resumen = { victorias: 259, partidas: 400, derrotas: 141 };

// Object.entries devuelve pares [clave, valor]; los destructuramos en el for.
// clave y valor listos en cada vuelta, sin acceso por índice ni por nombre
for (const [clave, valor] of Object.entries(resumen)) {
  // imprime 'victorias: 259', 'partidas: 400', etc.
  console.log(clave + ': ' + valor);
}

Estos dos patrones (for...of con objeto y for...of con Object.entries) aparecen constantemente cuando procesas listas de datos: los reconocerás de los array methods del Nivel 2 y los volverás a ver en React al recorrer props y estados.

Pruébalo tú#

Edita el código y pulsa Ejecutar (o Ctrl+Enter) para ver la consola. Empieza por añadir partidas al destructuring de la cabecera (const { nombre, region }) y loguéalo. Luego prueba a cambiar el bucle for...of para usar destructuring en la cabecera del bucle.

Comprueba lo que sabes#

Pregunta 1 de 6

Tienes const heroe = { nombre: "Tracer", rol: "Daño" }. ¿Qué hace const { nombre } = heroe?

Tu turno#

Leerlo no es lo mismo que saber escribirlo. Resuélvelo aquí mismo: edita solucion.js, muestra por la consola la cabecera del equipo y una ficha por héroe. El salto de nivel está en cómo uses el destructuring: anidado para el rango, en los parámetros para la ficha, y con for...of para el recorrido. Cuando lo tengas (o si te atascas), despliega las soluciones y fíjate en el salto de un nivel al siguiente.

Ejercicio · en esta página

Fichas de héroes con destructuring

A partir de la lista de héroes y del objeto equipo, muestra por la consola la cabecera del equipo y una ficha por héroe (nombre, rol, winrate y rango), usando destructuring en vez de repetir heroe. por todas partes. Si un héroe no trae rango, muestra "Sin clasificar".

Paso 1: Que funcione

  • La cabecera muestra nombre y región del equipo.
  • Cada ficha muestra nombre, rol, winrate y rango.
  • Todo se ve en la consola (vale acceder con punto).
Ver soluciones
// ════════════════════════════════════════════════════════════════════════════
// NIVEL OK — "que funcione"
//
// Resuelve el problema con lo mínimo: un destructuring de objeto sencillo para
// la cabecera y, para cada héroe, acceso con punto (heroe.nombre, heroe.rol…).
// Funciona y muestra los datos correctos, que es el primer requisito.
//
// Sus límites (los pule el nivel Mejor):
//   - El winrate se muestra como 0.65 en bruto, no como 65.0%.
//   - El rango se lee con heroe.stats.rango: si un héroe no trae rango, sale
//     "undefined" en la consola en vez de un texto decente.
//   - Repite heroe. por todas partes dentro de la ficha.
// ════════════════════════════════════════════════════════════════════════════

// Copia autocontenida de los datos para ejecutar esta solución suelta.
const heroes = [
  {
    nombre: "Tracer",
    rol: "Daño",
    partidas: 120,
    victorias: 78,
    stats: { rango: "Diamante", mvp: 12 },
  },
  {
    nombre: "Reinhardt",
    rol: "Tanque",
    partidas: 90,
    victorias: 51,
    stats: { rango: "Platino", mvp: 7 },
  },
  {
    nombre: "Mercy",
    rol: "Apoyo",
    partidas: 200,
    victorias: 130,
    stats: { rango: "Maestro", mvp: 21 },
  },
  {
    nombre: "Genji",
    rol: "Daño",
    partidas: 150,
    victorias: 72,
    stats: { mvp: 9 },
  },
  {
    nombre: "Ana",
    rol: "Apoyo",
    partidas: 110,
    victorias: 66,
    stats: { rango: "Diamante", mvp: 14 },
  },
  {
    nombre: "Winston",
    rol: "Tanque",
    partidas: 80,
    victorias: 38,
    stats: { rango: "Oro", mvp: 4 },
  },
];
const equipo = {
  nombre: "Los Vengadores de King's Row",
  region: "Europa",
  alineacion: ["Mercy", "Reinhardt", "Tracer"],
};

// ─── 1) Cabecera del equipo ─────────────────────────────────────────────────
function cabeceraEquipo(equipo) {
  // Destructuring de objeto: sacamos nombre y region en una línea.
  // equivale a equipo.nombre y equipo.region
  const { nombre, region } = equipo;
  // los usamos por su nombre
  console.log("Equipo: " + nombre);
  console.log("Región: " + region);
}

// ─── 2) Ficha de un héroe ───────────────────────────────────────────────────
function fichaHeroe(heroe) {
  // Acceso con punto, repitiendo heroe. en cada campo (funciona, pero verboso).
  // winrate en bruto: 0.65
  const winrate = heroe.victorias / heroe.partidas;
  // nombre del héroe
  console.log("--- " + heroe.nombre + " ---");
  // su rol
  console.log("Rol: " + heroe.rol);
  // se ve 0.65, sin formatear
  console.log("Winrate: " + winrate);
  // si no hay rango, sale undefined
  console.log("Rango: " + heroe.stats.rango);
}

// ─── 3) Mostrar ─────────────────────────────────────────────────────────────
function mostrar() {
  cabeceraEquipo(equipo);
  for (let i = 0; i < heroes.length; i++) {
    // ficha de cada héroe
    fichaHeroe(heroes[i]);
  }
}

mostrar();

Por qué este nivel

  • Resuelve con un destructuring básico para la cabecera y acceso con punto (heroe.nombre, heroe.stats.rango) para las fichas.
  • Funciona y muestra los datos, que es el primer requisito.
  • Sus límites: el winrate sale en bruto (0.65), el héroe sin rango muestra "undefined" y se repite heroe. en cada campo.