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.
