Objetos en JavaScript: propiedades, spread y destructuring
Actualizado el 29 de septiembre de 2026
Un objeto agrupa datos relacionados bajo nombres: un producto con su nombre, precio y stock; un usuario con su correo y su ciudad. Casi todos los datos con los que trabaja una aplicación web (lo que llega de una API, lo que se guarda en una base de datos) son objetos o arrays de objetos.
En esta guía vas a ver cómo leer y modificar objetos, recorrerlos, copiarlos sin modificar el original y la desestructuración (destructuring), una sintaxis que vas a encontrar en todo el código moderno.
Crear un objeto y leer sus propiedades
const producto = { nombre: "Polerón", precio: 19990, tallas: ["S", "M", "L"] };
producto.nombre // 'Polerón'
producto["precio"] // 19990
producto.tallas[1] // 'M'
producto.color // undefined (no existe, pero no es un error)
const campo = "precio";
producto[campo] // 19990 — con corchetes se puede usar una variableLa notación de punto es la habitual. Los corchetes son necesarios cuando el nombre de la propiedad está en una variable o no es un nombre válido (por ejemplo, si tiene espacios).
Agregar, cambiar y eliminar
producto.stock = 12; // agrega
producto.precio = 17990; // modifica
delete producto.tallas; // elimina
// producto → { nombre: 'Polerón', precio: 17990, stock: 12 }
"stock" in producto // true
Object.hasOwn(producto, "color") // falseRecorrer un objeto
Object.keys(producto) // ['nombre', 'precio', 'stock']
Object.values(producto) // ['Polerón', 17990, 12]
for (const [clave, valor] of Object.entries(producto)) {
console.log(`${clave}: ${valor}`);
}
// nombre: Polerón
// precio: 17990
// stock: 12Object.entries() convierte el objeto en un array de pares [clave, valor], que se recorre con for...of. Al convertirlo en array, también se pueden usar map, filter y el resto de los métodos de array.
Copiar y combinar con spread
const oferta = { ...producto, precio: 15990 };
producto.precio // 17990 (el original no cambió)
oferta.precio // 15990{ ...objeto } copia todas las propiedades en un objeto nuevo, y las que se escriben después reemplazan a las copiadas. Es la forma estándar de "modificar" un objeto sin tocar el original, algo que frameworks como React exigen.
Destructuring
La desestructuración saca propiedades de un objeto (o elementos de un array) y las guarda en variables, en una línea:
const { nombre, precio } = producto;
// nombre → 'Polerón', precio → 17990
const { color = "negro", nombre: titulo } = producto;
// color → 'negro' (valor por defecto, porque no existe)
// titulo → 'Polerón' (renombrado)
const [primero, , tercero] = ["a", "b", "c"];
// primero → 'a', tercero → 'c'Donde más se usa es en los parámetros de una función: la función declara qué propiedades necesita, y quien la llama pasa un objeto.
function mostrar({ nombre, precio }) {
return `${nombre}: $${precio}`;
}
mostrar(producto); // 'Polerón: $17990'Encadenamiento opcional: ?.
const usuario = { perfil: { ciudad: "Talca" } };
usuario.perfil?.ciudad // 'Talca'
usuario.direccion?.calle // undefined, sin error
usuario.direccion?.calle ?? "sin dirección" // 'sin dirección'?. deja de avanzar y devuelve undefined si lo que está a su izquierda es null o undefined. Combinado con ?? sirve para leer datos que pueden faltar, algo muy común con respuestas de APIs.
Errores comunes
Leer una propiedad de undefined
usuario.direccion.calle lanza TypeError: Cannot read properties of undefined (reading 'calle') si direccion no existe. Es probablemente el error más común de JavaScript. Revisa de dónde viene el dato, o usa ?. si es normal que falte.
objeto.variable en vez de objeto[variable]
Con const campo = "precio", producto.campo busca una propiedad que se llama literalmente "campo" y devuelve undefined. Para usar el valor de la variable como nombre, escribe producto[campo].
La copia con spread es superficial
const original = { nombre: "Ana", notas: [5, 6] };
const copia = { ...original };
copia.nombre = "Luis"; // no afecta al original
copia.notas.push(7); // ¡sí lo afecta!
// original → { nombre: 'Ana', notas: [5, 6, 7] }Spread copia el primer nivel. Los arrays y objetos de adentro se comparten entre el original y la copia. Para copiar todo en profundidad existe structuredClone(original).
Comparar objetos con ===
{ a: 1 } === { a: 1 } es false: son dos objetos distintos aunque tengan el mismo contenido. === solo es true si ambos lados son el mismo objeto.
Ejercicios resueltos
Intenta resolver cada ejercicio antes de abrir la solución: equivocarse y corregir es la parte que más enseña.
1.Resumen de un producto
Escribe una función resumenProducto que reciba un objeto con nombre, precio y stock (opcional, 0 si falta) y devuelva un texto como "Polerón ($19990): 3 disponibles", o "agotado" en vez de la cantidad si no hay stock. Usa destructuring en el parámetro.
resumenProducto({ nombre: "Polerón", precio: 19990, stock: 3 })→"Polerón ($19990): 3 disponibles"resumenProducto({ nombre: "Gorro", precio: 5990 })→"Gorro ($5990): agotado"
function resumenProducto(/* ... */) {
// ...
}Ver soluciónOcultar solución
function resumenProducto({ nombre, precio, stock = 0 }) {
const disponibilidad = stock > 0 ? `${stock} disponibles` : "agotado";
return `${nombre} ($${precio}): ${disponibilidad}`;
}El parámetro desestructurado deja a la vista qué propiedades usa la función, y stock = 0 resuelve el caso en que falta. Separar la disponibilidad en su propia variable evita meter un ternario dentro del template literal, que se vuelve difícil de leer. El $ antes de ${precio} es un signo de peso literal.
2.Contar palabras
Escribe una función contarPalabras(texto) que devuelva un objeto con cuántas veces aparece cada palabra, sin distinguir mayúsculas e ignorando espacios repetidos.
contarPalabras("el sol y el mar")→{ el: 2, sol: 1, y: 1, mar: 1 }contarPalabras("Hola hola")→{ hola: 2 }contarPalabras("")→{}
function contarPalabras(texto) {
// ...
}Ver soluciónOcultar solución
function contarPalabras(texto) {
const conteo = {};
const palabras = texto.toLowerCase().split(" ").filter((p) => p !== "");
for (const palabra of palabras) {
conteo[palabra] = (conteo[palabra] ?? 0) + 1;
}
return conteo;
}Cada palabra es una clave y su valor es la cantidad. conteo[palabra] ?? 0 devuelve la cantidad actual o 0 si la palabra aparece por primera vez. Aquí la palabra está en una variable, así que hay que usar corchetes.
El filter quita los textos vacíos que genera split(" ") con espacios repetidos o con un texto vacío ("".split(" ") devuelve [""], no un array vacío).
3.Actualizar sin modificar el original
Escribe una función actualizarUsuario(usuario, cambios) que devuelva un objeto nuevo con los datos del usuario y los cambios aplicados, sin modificar el objeto original.
const u = { nombre: "Ana", ciudad: "Talca", edad: 30 };
const u2 = actualizarUsuario(u, { ciudad: "Santiago" });
// u2 → { nombre: 'Ana', ciudad: 'Santiago', edad: 30 }
// u → { nombre: 'Ana', ciudad: 'Talca', edad: 30 } (sin cambios)function actualizarUsuario(usuario, cambios) {
// ...
}Ver soluciónOcultar solución
function actualizarUsuario(usuario, cambios) {
return { ...usuario, ...cambios };
}Se copian primero las propiedades del usuario y después las de los cambios. Cuando una propiedad está en ambos, gana la que viene después, así que ciudad queda en "Santiago". Hacer usuario.ciudad = cambios.ciudad también daría el resultado, pero modificaría el objeto original, que es justo lo que se pide evitar.