Destructuring de objetos en JavaScript | Nicolás GarzónEl destructuring de objetos permite extraer propiedades y guardarlas en bindings locales.
JavaScript
const user = {
name: "Nicolás",
role: "developer",
};
const { name, role } = user;
Equivale conceptualmente a:
JavaScript
const name = user.name;
const role = user.role;
JavaScript
const product = {
name: "Keyboard",
price: 120,
};
const { price } = product;
JavaScript busca una propiedad llamada price.
El orden escrito no importa.
JavaScript
const { price, name } = product;
Los objetos no se destructuran por posición, sino por clave.
JavaScript
const { name: productName } = product;
name es la propiedad buscada.
productName es el binding local creado.
Después de esta declaración:
JavaScript
console.log(productName);
console.log(name);
JavaScript
const { currency = "USD" } = product;
El valor por defecto se utiliza únicamente cuando la propiedad vale undefined o no existe.
JavaScript
const settings = {
theme: null,
pageSize: 0,
};
const {
theme = "light",
pageSize = 20,
} = settings;
console.log(theme);
console.log(pageSize);
null, 0, false y "" no activan el valor por defecto.
JavaScript
const {
currency: selectedCurrency = "USD",
} = product;
Primero se busca currency; después el valor se guarda como selectedCurrency.
JavaScript
const order = {
customer: {
profile: {
name: "Nicolás",
},
},
};
const {
customer: {
profile: { name },
},
} = order;
Este patrón crea name, pero no crea automáticamente bindings llamados customer o profile.
JavaScript
console.log(name);
console.log(customer);
Los patrones muy profundos pueden ser frágiles y difíciles de leer. En esos casos puede ser mejor dividir la extracción.
JavaScript
const { customer } = order;
const { profile } = customer;
const { name } = profile;
Esto falla si customer es undefined:
JavaScript
const {
customer: { name },
} = order;
Una alternativa es dar un objeto por defecto.
JavaScript
const {
customer: { name } = {},
} = order;
Pero si order puede ser null o undefined, el destructuring exterior también falla.
JavaScript
const { customer } = order ?? {};
No conviertas patrones complejos en un reemplazo de una validación necesaria.
JavaScript
const user = {
id: "user-123",
name: "Nicolás",
passwordHash: "secret",
};
const { passwordHash, ...publicUser } = user;
publicUser recibe las demás propiedades propias enumerables.
JavaScript
console.log(publicUser);
La copia es superficial. Los objetos anidados continúan compartiendo referencias.
Rest debe aparecer al final del patrón.
JavaScript
const { ...rest, id } = user;
JavaScript
function printUser({ name, role }) {
console.log(`${name}: ${role}`);
}
Hace explícitas las propiedades utilizadas por la función.
También puede incluir un valor por defecto para el argumento completo.
JavaScript
function createButton({
label = "Continue",
disabled = false,
} = {}) {
return { label, disabled };
}
Sin = {}, llamar createButton() produciría un error al intentar destructurar undefined.
JavaScript
function greet({ name = "Guest" } = {}) {
return `Hello, ${name}`;
}
JavaScript
greet();
greet({});
greet({ name: undefined });
greet({ name: null });
En una declaración nueva:
JavaScript
const { name } = user;
Para asignar sobre bindings existentes necesitas paréntesis.
JavaScript
let name;
let role;
({ name, role } = user);
Sin paréntesis, las llaves pueden interpretarse como un bloque.
JavaScript
const field = "email";
const user = {
email: "nico@example.com",
};
const { [field]: value } = user;
value recibe la propiedad cuyo nombre está en field.
JavaScript
const { name } = user;
El objeto original no cambia.
JavaScript
const { passwordHash, ...publicUser } = user;
passwordHash sigue existiendo en user. Solo se construye otro objeto que no la incluye.
El patrón puede leer una propiedad heredada.
JavaScript
const base = {
role: "viewer",
};
const user = Object.create(base);
const { role } = user;
console.log(role);
Sin embargo, object rest recoge propiedades propias enumerables, no heredadas.
Los valores por defecto se evalúan solo cuando son necesarios.
JavaScript
function createId() {
console.log("Generating ID");
return crypto.randomUUID();
}
const { id = createId() } = record;
Si record.id existe y no es undefined, createId no se ejecuta.
JavaScript
function createRequestOptions({
method = "GET",
headers = {},
timeout = 5000,
...extraOptions
} = {}) {
return {
method: method.toUpperCase(),
headers,
timeout,
...extraOptions,
};
}
- Expone opciones conocidas.
- Define defaults claros.
- Conserva opciones adicionales.
- Devuelve un objeto normalizado.
Destructuring no siempre mejora la lectura.
JavaScript
const {
configuration: {
application: {
services: {
orders: {
endpoints: { create },
},
},
},
},
} = settings;
El patrón oculta el camino y falla si falta cualquier nivel. Dividir el acceso o usar optional chaining puede ser más claro.
También evita extraer demasiadas propiedades si la relación con el objeto ayuda a entenderlas.
JavaScript
order.status;
order.total;
order.customer;
Puede ser más expresivo que varios nombres sueltos en un scope grande.
- Pensar que el orden del patrón importa.
- Confundir la propiedad original con el nombre local renombrado.
- Esperar que un default reemplace
null, 0 o false.
- Destructurar
null o undefined sin validar.
- Crear patrones anidados difíciles de mantener.
- Pensar que rest realiza una copia profunda.
- Suponer que destructuring elimina propiedades del objeto original.
- Olvidar
= {} en parámetros opcionales.
- Omitir paréntesis al asignar sobre variables existentes.
- Extraer tantas propiedades que se pierde el contexto del objeto.
- El destructuring de objetos trabaja por claves, no por posición.
property: localName permite renombrar.
- Los defaults solo reemplazan
undefined.
- Los patrones pueden anidarse, pero necesitan estructuras existentes.
- Rest recoge las demás propiedades propias enumerables.
- La copia generada por rest es superficial.
- Destructuring puede utilizarse en parámetros.
- El objeto original no se modifica.
- La claridad debe importar más que reducir líneas.
¿Qué valores se obtienen?
JavaScript
const settings = {
theme: null,
pageSize: 0,
};
const {
theme = "light",
pageSize = 20,
language = "es",
} = settings;
Respuesta
theme vale null, pageSize vale 0 y language vale "es". Los defaults solo se usan para propiedades ausentes o con valor undefined.
Spread, rest y copias diferencia las dos funciones de ... y explica qué información se expande, agrupa o copia.