Tema
Objetos
Un usuario tiene nombre, correo y edad. Un producto tiene precio, stock y categoría. Para representar "cosas" con varias características, JavaScript usa objetos. Son la estructura de datos más importante del lenguaje: las respuestas de las APIs, la configuración de las librerías y el estado de tus apps son objetos.
Concepto
Un objeto es como una ficha de registro: cada campo tiene una etiqueta (la clave o propiedad) y un contenido (el valor). Mientras que un array guarda cosas por posición (0, 1, 2), un objeto las guarda por nombre.
js
const usuario = {
nombre: 'Ana López', // clave: valor
edad: 28,
activo: true,
intereses: ['diseño', 'café'], // un valor puede ser un array
direccion: { // ...u otro objeto
ciudad: 'Guadalajara',
cp: '44100'
}
};Los valores pueden ser de cualquier tipo, incluso funciones (a esas se les llama métodos).
Acceder y modificar propiedades
js
// Notación de punto (la más común)
console.log(usuario.nombre); // 'Ana López'
console.log(usuario.direccion.ciudad); // 'Guadalajara'
// Notación de corchetes: cuando la clave está en una variable
// o tiene caracteres especiales
const campo = 'edad';
console.log(usuario[campo]); // 28
const config = { 'color-fondo': '#fff' };
console.log(config['color-fondo']);
// Modificar
usuario.edad = 29;
// Agregar una propiedad nueva
usuario.telefono = '33 1234 5678';
// Eliminar
delete usuario.activo;
// ¿Existe la propiedad?
console.log('telefono' in usuario); // true
console.log(Object.hasOwn(usuario, 'activo')); // false
// Leer una propiedad que no existe NO da error: da undefined
console.log(usuario.apellido); // undefinedconst no congela el objeto
const usuario = {...} impide reasignar la variable (usuario = otraCosa), pero sí puedes cambiar sus propiedades. Si quieres un objeto realmente inmutable usa Object.freeze(usuario).
Atajos modernos al crear objetos
js
const nombre = 'Mouse';
const precio = 349;
// Propiedades abreviadas: si la variable se llama igual que la clave
const producto = { nombre, precio }; // { nombre: 'Mouse', precio: 349 }
// Claves calculadas
const campo = 'color';
const opciones = { [campo]: 'negro', [`${campo}Secundario`]: 'gris' };
// { color: 'negro', colorSecundario: 'gris' }Métodos y this
Un método es una función guardada en un objeto. Dentro de él, this apunta al objeto que lo llamó.
js
const carrito = {
items: [],
agregar(producto) { // sintaxis corta de método
this.items.push(producto);
return this; // permite encadenar
},
total() {
return this.items.reduce((suma, p) => suma + p.precio, 0);
}
};
carrito.agregar({ nombre: 'Mouse', precio: 349 })
.agregar({ nombre: 'Teclado', precio: 1299 });
console.log(carrito.total()); // 1648Error común
No uses funciones flecha como métodos si necesitas this. Las flechas no tienen su propio this: toman el del lugar donde se escribieron.
js
const persona = {
nombre: 'Luis',
saludarMal: () => `Hola, soy ${this.nombre}`, // this NO es persona
saludarBien() { return `Hola, soy ${this.nombre}`; }
};
persona.saludarMal(); // 'Hola, soy undefined'
persona.saludarBien(); // 'Hola, soy Luis'Profundizaremos en this en POO y clases.
Recorrer objetos
js
const precios = { cafe: 45, te: 35, pan: 20 };
Object.keys(precios); // ['cafe', 'te', 'pan']
Object.values(precios); // [45, 35, 20]
Object.entries(precios); // [['cafe', 45], ['te', 35], ['pan', 20]]
// Recorrer con for...of + entries y desestructuración
for (const [producto, precio] of Object.entries(precios)) {
console.log(`${producto}: $${precio}`);
}
// Sumar valores
const total = Object.values(precios).reduce((a, b) => a + b, 0); // 100
// Transformar un objeto: entries → map → fromEntries
const conDescuento = Object.fromEntries(
Object.entries(precios).map(([k, v]) => [k, v * 0.9])
);Desestructuración
La desestructuración te permite sacar valores de un objeto o array en variables, en una sola línea.
De objetos
js
const pedido = {
id: 1024,
cliente: { nombre: 'María', email: 'maria@correo.com' },
total: 1850,
estado: 'enviado'
};
// Básica
const { id, total } = pedido;
// Renombrar
const { estado: estadoPedido } = pedido;
// Valor por defecto si no existe
const { metodoPago = 'tarjeta' } = pedido;
// Anidada
const { cliente: { nombre, email } } = pedido;
// En parámetros de función (¡muy usado!)
function mostrarPedido({ id, total, estado = 'pendiente' }) {
return `Pedido #${id}: $${total} (${estado})`;
}
mostrarPedido(pedido);Buena práctica
Cuando una función recibe más de 2 o 3 parámetros, pásale un objeto y desestructúralo. Así no importa el orden y el código que la llama se lee solo: crearUsuario({ nombre: 'Ana', rol: 'admin' }).
De arrays
js
const colores = ['rojo', 'verde', 'azul', 'negro'];
const [primero, segundo] = colores; // 'rojo', 'verde'
const [, , tercero] = colores; // saltar posiciones: 'azul'
const [cabeza, ...resto] = colores; // 'rojo', ['verde', 'azul', 'negro']
// Intercambiar variables
let a = 1, b = 2;
[a, b] = [b, a];Spread y rest (...)
Los tres puntos hacen dos cosas opuestas según dónde estén:
- Spread (expandir): "desempaca" un objeto o array.
- Rest (agrupar): "empaca" lo que sobra.
js
// SPREAD en objetos: copiar y combinar
const base = { color: 'azul', talla: 'M' };
const copia = { ...base };
const actualizado = { ...base, talla: 'L' }; // sobrescribe talla
const combinado = { ...base, ...{ precio: 299 } };
// Configuración con valores por defecto (patrón muy común)
function crearBoton(opciones) {
const config = { texto: 'Enviar', color: 'primario', deshabilitado: false, ...opciones };
return config;
}
crearBoton({ color: 'peligro' });
// { texto: 'Enviar', color: 'peligro', deshabilitado: false }
// SPREAD en arrays
const frutas = ['manzana', 'pera'];
const masFrutas = [...frutas, 'uva'];
Math.max(...[3, 9, 2]); // 9
// REST: quitar una propiedad sin mutar
const usuario = { id: 1, nombre: 'Ana', password: '123456' };
const { password, ...usuarioPublico } = usuario;
// usuarioPublico = { id: 1, nombre: 'Ana' }Copia superficial vs. profunda
Los objetos se guardan por referencia: la variable no contiene el objeto, sino la "dirección" donde vive.
js
const original = { nombre: 'Ana' };
const otra = original; // NO es una copia: es la misma dirección
otra.nombre = 'Luis';
console.log(original.nombre); // 'Luis' 😱El spread crea una copia superficial: copia el primer nivel, pero los objetos anidados siguen compartidos.
js
const perfil = { nombre: 'Ana', direccion: { ciudad: 'CDMX' } };
const copia = { ...perfil };
copia.nombre = 'Luis'; // no afecta al original ✅
copia.direccion.ciudad = 'Monterrey'; // ¡sí afecta al original! ❌
// Copia profunda nativa
const copiaProfunda = structuredClone(perfil);
copiaProfunda.direccion.ciudad = 'Puebla'; // el original queda intacto ✅Error común
Comparar objetos con === compara referencias, no contenido: { a: 1 } === { a: 1 } es false. Para comparar contenido simple puedes usar JSON.stringify(a) === JSON.stringify(b) (cuidado: el orden de las claves importa).
Optional chaining y nullish coalescing
Cuando trabajas con datos de APIs, muchas propiedades pueden faltar.
js
const respuesta = { usuario: { perfil: null } };
// Sin optional chaining: error si algo es null/undefined
// respuesta.usuario.perfil.foto → TypeError
respuesta.usuario?.perfil?.foto; // undefined, sin error
respuesta.usuario?.perfil?.foto ?? '/img/avatar.png'; // valor por defecto
// También con métodos y corchetes
respuesta.usuario.saludar?.();
respuesta.items?.[0];Caso real: normalizar la respuesta de una API
js
// Lo que llega de una API (estructura incómoda)
const apiUsuario = {
id: 7,
name: 'Carlos Ruiz',
email: 'carlos@empresa.mx',
address: { city: 'Mérida', geo: { lat: '20.96', lng: '-89.62' } },
company: null
};
// Lo que tu app necesita (estructura limpia)
function normalizarUsuario({ id, name, email, address, company }) {
return {
id,
nombre: name,
email: email.toLowerCase(),
ciudad: address?.city ?? 'Sin ciudad',
empresa: company?.name ?? 'Independiente',
coordenadas: {
lat: Number(address?.geo?.lat),
lng: Number(address?.geo?.lng)
}
};
}
console.log(normalizarUsuario(apiUsuario));Ejercicios
- Crea un objeto
librocon título, autor, año y un métodoresumen()que devuelva"Cien años de soledad - Gabriel García Márquez (1967)". - Dado
const config = { tema: 'claro', idioma: 'es' }, crea una nueva configuración contema: 'oscuro'ynotificaciones: truesin modificar la original. - Escribe una función
saludarque reciba un objeto y use desestructuración con valor por defecto:saludar({ nombre: 'Ana' })→"Hola, Ana";saludar({})→"Hola, invitado". - Dado
const inventario = { manzanas: 10, peras: 0, uvas: 25 }, obtén un array con los nombres de las frutas que sí tienen existencias. - Quita la propiedad
tokendeconst sesion = { usuario: 'ana', token: 'abc', expira: 3600 }sin usardelete.
Ver solución
js
// 1
const libro = {
titulo: 'Cien años de soledad',
autor: 'Gabriel García Márquez',
anio: 1967,
resumen() {
return `${this.titulo} - ${this.autor} (${this.anio})`;
}
};
// 2
const config = { tema: 'claro', idioma: 'es' };
const nuevaConfig = { ...config, tema: 'oscuro', notificaciones: true };
// 3
function saludar({ nombre = 'invitado' } = {}) {
return `Hola, ${nombre}`;
}
// 4
const inventario = { manzanas: 10, peras: 0, uvas: 25 };
const disponibles = Object.entries(inventario)
.filter(([, cantidad]) => cantidad > 0)
.map(([fruta]) => fruta); // ['manzanas', 'uvas']
// 5
const sesion = { usuario: 'ana', token: 'abc', expira: 3600 };
const { token, ...sesionSegura } = sesion;Resumen
- Un objeto agrupa datos relacionados en pares
clave: valor; accedes con.o[]. - Los métodos son funciones dentro del objeto; usa sintaxis de método (no flecha) si necesitas
this. Object.keys,valuesyentrieste permiten recorrer y transformar objetos.- La desestructuración extrae valores; el spread copia y combina; el rest agrupa lo que sobra.
- Los objetos se copian por referencia: usa spread para copias superficiales y
structuredClonepara profundas. ?.y??te protegen de datos incompletos.
Siguiente: Strings y template literals