1. Objetos Literales: Entendiendo el Concepto
¿Qué es realmente un Objeto? (Analogía)
Imagina que tienes una Mochila.
Hasta ahora, si querías guardar datos, usabas variables sueltas (`let colorMochila`, `let pesoMochila`, `let bolsillos`). Pero si tienes 50 mochilas, ¡es un caos de variables!
Un Objeto es esa mochila completa. Es una "super-caja" donde guardas todo lo relacionado con una cosa específica, organizada por etiquetas.
- Las Propiedades son las características (color, tamaño, marca).
- Los Métodos son las cosas que puede HACER (abrirse, cerrarse, romperse).
En desarrollo web, usamos objetos para TODO:
- Un Usuario: Tiene nombre, email, contraseña, foto (propiedades) y puede iniciar sesión o salir (métodos).
- Un Botón: Tiene color, tamaño, texto (propiedades) y reacciona al click (método).
- Un Producto de Tienda: Tiene precio, stock, descripción, imágenes.
Sintaxis: Creando tu primer objeto
Se usan las llaves {}. Dentro ponemos pares de clave: valor.
Sintaxis Básica
// Crear un objeto vacío
const persona = {};
// Objeto con propiedades
const coche = {
marca: 'Toyota',
modelo: 'Corolla',
año: 2023,
color: 'rojo'
};
console.log(coche.marca); // "Toyota"
console.log(coche['año']); // 2023
Propiedades Calculadas (ES6+)
Puedes usar expresiones como nombres de propiedades:
const propiedad = 'nombre';
const valor = 'Juan';
const usuario = {
[propiedad]: valor, // nombre: "Juan"
['edad' + 'Usuario']: 25 // edadUsuario: 25
};
console.log(usuario.nombre); // "Juan"
console.log(usuario.edadUsuario); // 25
Shorthand Properties (Atajo de Propiedades)
const nombre = 'Ana';
const edad = 30;
// ? Forma antigua
const persona1 = {
nombre: nombre,
edad: edad
};
// ? ES6: Si la variable tiene el mismo nombre, puedes omitir
const persona2 = {
nombre, // Equivale a nombre: nombre
edad // Equivale a edad: edad
};
console.log(persona2); // { nombre: "Ana", edad: 30 }
Comparación: Array vs Objeto
Los datos van en vagones numerados (0, 1, 2...). El orden importa.
let tren = ["Rojo", "Grande"];
// ¿Qué es "Rojo"? ¿Color o nombre?
// No se sabe sin contexto.
Cada herramienta tiene su sitio específico con una etiqueta. El orden NO importa.
let caja = { color: "Rojo", tamaño: "Grande" };
// Aquí sabemos exactamente qué es cada dato.
Mezclando todo: Propiedades y Métodos a la vez
Puedes (y debes) definir qué ES el objeto y qué HACE al mismo tiempo.
const superheroe = {
// --- PROPIEDADES (Lo que ES) ---
nombre: 'Iron Man',
poder: 'Tecnología',
vida: 100,
// --- MÉTODOS (Lo que HACE) ---
saludar() {
return "¡Hola! Soy " + this.nombre;
},
atacar() {
this.vida -= 10; // Puede cambiar sus propias propiedades
return "¡Rayos Repulsores! Vida restante: " + this.vida;
}
};
console.log(superheroe.nombre); // "Iron Man"
console.log(superheroe.saludar()); // "¡Hola! Soy Iron Man"
console.log(superheroe.atacar()); // "¡Rayos Repulsores! Vida restante: 90"
🤔 ¿Y si quiero crear a Spiderman, Superman, y Batman?
¡Exacto! Copiar y pegar este código 3 veces sería terrible.
Los Objetos Literales (los de este módulo) son para cosas únicas (TU configuración, TU usuario actual).
Para crear muchos objetos iguales (Fábrica de Superhéroes), usamos
CLASES.
👉 Ir al Módulo 09: Programación Orientada a Objetos
(Clases)
para aprender a hacer "moldes".
this. Si necesitas
usar this dentro de un método, usa la sintaxis tradicional o shorthand.
2. Acceso y Modificación de Propiedades
Dot Notation vs Bracket Notation
const usuario = {
nombre: 'Carlos',
'nombre completo': 'Carlos García',
edad: 28
};
// Dot notation (punto)
console.log(usuario.nombre); // "Carlos"
// Bracket notation (corchetes) - necesario si:
// 1. La propiedad tiene espacios
console.log(usuario['nombre completo']); // "Carlos García"
// 2. La propiedad está en una variable
const prop = 'edad';
console.log(usuario[prop]); // 28
// 3. La propiedad se calcula dinámicamente
const dato = 'nom';
console.log(usuario[dato + 'bre']); // "Carlos"
Añadir, Modificar y Eliminar
const persona = { nombre: 'Laura' };
// Añadir propiedad
persona.edad = 25;
persona['ciudad'] = 'Madrid';
// Modificar
persona.nombre = 'Laura Martínez';
// Eliminar
delete persona.ciudad;
console.log(persona); // { nombre: "Laura Martínez", edad: 25 }
Verificar Existencia de Propiedades
const coche = { marca: 'Ford', año: 2020 };
// in operator
console.log('marca' in coche); // true
console.log('color' in coche); // false
// hasOwnProperty (no incluye herencia)
console.log(coche.hasOwnProperty('marca')); // true
// Verificar si es undefined
console.log(coche.color !== undefined); // false
3. Destructuring de Objetos ?
El destructuring es una sintaxis que permite "desempaquetar" valores de objetos (o arrays) en variables individuales.
Sintaxis Básica
const persona = {
nombre: 'María',
edad: 32,
ciudad: 'Barcelona'
};
// ? Forma antigua
const nombre = persona.nombre;
const edad = persona.edad;
const ciudad = persona.ciudad;
// ? Destructuring (ES6)
const { nombre, edad, ciudad } = persona;
console.log(nombre); // "María"
console.log(edad); // 32
console.log(ciudad); // "Barcelona"
Renombrar Variables
const usuario = {
nombre: 'Pedro',
edad: 40
};
// Renombrar: { propiedadObjeto: nuevoNombre }
const { nombre: nombreUsuario, edad: años } = usuario;
console.log(nombreUsuario); // "Pedro"
console.log(años); // 40
// console.log(nombre); // ? Error: nombre is not defined
Valores por Defecto
const config = {
tema: 'oscuro'
// idioma no existe
};
// Si la propiedad no existe, usa el valor por defecto
const { tema, idioma = 'español' } = config;
console.log(tema); // "oscuro"
console.log(idioma); // "español" (valor por defecto)
Destructuring Anidado
const empresa = {
nombre: 'TechCorp',
direccion: {
calle: 'Gran Vía',
numero: 123,
ciudad: 'Madrid'
}
};
// Destructuring anidado
const {
nombre,
direccion: { ciudad, numero }
} = empresa;
console.log(nombre); // "TechCorp"
console.log(ciudad); // "Madrid"
console.log(numero); // 123
// console.log(direccion); // ? Error: direccion no está definida
Destructuring en Parámetros de Función
// ? Forma antigua
function mostrarUsuario(usuario) {
console.log(usuario.nombre + ' tiene ' + usuario.edad + ' años');
}
// ? Con destructuring
function mostrarUsuarioModerno({ nombre, edad }) {
console.log(`${nombre} tiene ${edad} años`);
}
const user = { nombre: 'Sara', edad: 28 };
mostrarUsuarioModerno(user); // "Sara tiene 28 años"
// Con valores por defecto
function crearUsuario({ nombre, rol = 'usuario' }) {
return { nombre, rol };
}
console.log(crearUsuario({ nombre: 'Luis' }));
// { nombre: "Luis", rol: "usuario" }
4. Spread y Rest Operators (...)
Spread Operator (Expandir)
El operador ... "expande" un objeto en sus propiedades individuales:
// Copiar objetos
const original = { a: 1, b: 2 };
const copia = { ...original };
console.log(copia); // { a: 1, b: 2 }
console.log(copia === original); // false (son diferentes objetos)
// Combinar objetos
const datosBasicos = { nombre: 'Ana', edad: 25 };
const contacto = { email: 'ana@mail.com', telefono: '666555444' };
const usuarioCompleto = {
...datosBasicos,
...contacto,
activo: true
};
console.log(usuarioCompleto);
// { nombre: "Ana", edad: 25, email: "ana@mail.com", telefono: "666555444", activo: true }
Sobrescribir Propiedades
const config = {
tema: 'claro',
idioma: 'es',
notificaciones: true
};
// Si hay propiedades duplicadas, la última gana
const nuevaConfig = {
...config,
tema: 'oscuro', // Sobrescribe tema
volumen: 80 // Nueva propiedad
};
console.log(nuevaConfig);
// { tema: "oscuro", idioma: "es", notificaciones: true, volumen: 80 }
Rest Operator (Recoger)
En destructuring, ... recoge las propiedades restantes:
const usuario = {
id: 1,
nombre: 'Carlos',
email: 'carlos@mail.com',
edad: 30,
ciudad: 'Valencia'
};
// "resto" recogerá todas las propiedades excepto id y nombre
const { id, nombre, ...resto } = usuario;
console.log(id); // 1
console.log(nombre); // "Carlos"
console.log(resto);
// { email: "carlos@mail.com", edad: 30, ciudad: "Valencia" }
Caso de Uso Real: Eliminar Propiedades
const producto = {
id: 123,
nombre: 'Laptop',
precio: 999,
stock: 5,
__interno: 'no enviar'
};
// Eliminar __interno sin mutarlo
const { __interno, ...productoLimpio } = producto;
console.log(productoLimpio);
// { id: 123, nombre: "Laptop", precio: 999, stock: 5 }
5. Optional Chaining (?.) - ES2020
El optional chaining permite acceder a propiedades anidadas sin causar errores si
alguna parte es null o undefined.
Problema sin Optional Chaining
const usuario = {
nombre: 'Pedro',
direccion: {
ciudad: 'Madrid'
// calle no existe
}
};
// ? Esto funciona
console.log(usuario.direccion.ciudad); // "Madrid"
// ? Esto causa ERROR
// console.log(usuario.contacto.telefono);
// Error: Cannot read property 'telefono' of undefined
// Forma antigua de evitar el error
const telefono = usuario.contacto && usuario.contacto.telefono;
console.log(telefono); // undefined (sin error)
Solución con Optional Chaining (?)
const usuario = {
nombre: 'Laura',
direccion: {
ciudad: 'Barcelona'
}
};
// ❌ Si 'direccion' no existiera, esto daría error sin el ?.
console.log(usuario.direccion?.ciudad); // "Barcelona"
console.log(usuario.contacto?.email); // undefined (sin error)
Nullish Coalescing (??) - ES2020
A diferencia de || (que falla si el valor es 0 o ""), el operador
?? solo devuelve el valor de la derecha si el de la izquierda es exactamente
null o undefined.
let stock = 0;
// Usando || (Mal para números)
let valor1 = stock || 10; // 10 (porque 0 es "falso")
// Usando ?? (Correcto)
let valor2 = stock ?? 10; // 0 (porque 0 es un valor válido)
let nombre = null;
let usuario = nombre ?? "Invitado"; // "Invitado"
Con Funciones
const api = {
obtenerDatos() {
return { total: 100 };
}
};
// Si el método existe, lo llama
console.log(api.obtenerDatos?.()); // { total: 100 }
// Si el método NO existe, devuelve undefined
console.log(api.enviarDatos?.()); // undefined (sin error)
Con Arrays
const datos = {
usuarios: ['Ana', 'Luis', 'Carlos']
};
console.log(datos.usuarios?.[0]); // "Ana"
console.log(datos.productos?.[0]); // undefined (sin error)
6. Nullish Coalescing (??) - ES2020
El operador ?? devuelve el valor de la derecha SOLO si el valor de la izquierda es
null o undefined.
Diferencia con OR (||)
const config = {
volumen: 0,
notificaciones: false,
tema: null
};
// ? Problema con ||
const vol1 = config.volumen || 50;
console.log(vol1); // 50 (incorrecto! 0 es falsy pero es válido)
const notif1 = config.notificaciones || true;
console.log(notif1); // true (incorrecto! false es válido)
// ? Solución con ??
const vol2 = config.volumen ?? 50;
console.log(vol2); // 0 (correcto! solo null/undefined se reemplazan)
const notif2 = config.notificaciones ?? true;
console.log(notif2); // false (correcto!)
const tema = config.tema ?? 'claro';
console.log(tema); // "claro" (tema era null)
| Valor | || (OR) | ?? (Nullish) |
|---|---|---|
null |
Usa default | Usa default |
undefined |
Usa default | Usa default |
0 |
Usa default ? | Devuelve 0 ? |
"" (string vacío) |
Usa default ? | Devuelve "" ? |
false |
Usa default ? | Devuelve false ? |
7. Métodos Útiles de Object
Object.keys()
Devuelve un array con las claves (propiedades) del objeto:
const persona = {
nombre: 'Ana',
edad: 25,
ciudad: 'Sevilla'
};
const claves = Object.keys(persona);
console.log(claves); // ["nombre", "edad", "ciudad"]
// Útil para iterar
claves.forEach(key => {
console.log(`${key}: ${persona[key]}`);
});
// nombre: Ana
// edad: 25
// ciudad: Sevilla
Object.values()
Devuelve un array con los valores:
const valores = Object.values(persona);
console.log(valores); // ["Ana", 25, "Sevilla"]
Object.entries()
Devuelve un array de arrays [clave, valor]:
const entradas = Object.entries(persona);
console.log(entradas);
// [["nombre", "Ana"], ["edad", 25], ["ciudad", "Sevilla"]]
// Destructuring en el bucle
for (const [clave, valor] of entradas) {
console.log(`${clave} = ${valor}`);
}
Object.assign() - Copiar/Combinar
const target = { a: 1 };
const source = { b: 2, c: 3 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 2, c: 3 }
// ? Más moderno: usar spread
const combinado = { ...target, ...source };
Object.freeze() - Inmutable
const constantes = Object.freeze({
PI: 3.14159,
MAX: 100
});
// ? Esto no tendrá efecto (modo estricto lanza error)
constantes.PI = 3;
console.log(constantes.PI); // 3.14159 (no cambió)
8. Ejemplo Práctico: Gestión de Usuarios
// Datos de usuario con toda la sintaxis moderna
const crearUsuario = ({ nombre, email, edad = 18, rol = 'user' }) => {
return {
id: Math.random().toString(36).substr(2, 9),
nombre,
email,
edad,
rol,
fechaCreacion: new Date(),
activo: true
};
};
// Crear usuarios
const user1 = crearUsuario({
nombre: 'Carlos',
email: 'carlos@example.com',
edad: 25
});
const user2 = crearUsuario({
nombre: 'Laura',
email: 'laura@example.com'
// edad usa default: 18
});
console.log(user1);
console.log(user2);
// Actualizar usuario sin mutar
const actualizarUsuario = (usuario, cambios) => {
return { ...usuario, ...cambios };
};
const userActualizado = actualizarUsuario(user1, {
edad: 26,
activo: false
});
console.log(userActualizado);
// Extraer solo los datos necesarios
const { id, nombre, email } = userActualizado;
console.log({ id, nombre, email });
// Obtener usuarios activos de una lista
const usuarios = [user1, user2, userActualizado];
const usuariosActivos = usuarios.filter(u => u.activo);
console.log('Activos:', usuariosActivos.length);
9. Ejercicios Prácticos
Ejercicio 1: Destructuring
Extrae titulo, autor y ciudad (del editor):
const libro = {
titulo: '1984',
autor: 'George Orwell',
año: 1949,
editor: {
nombre: 'Secker & Warburg',
ciudad: 'Londres'
}
};
// Tu código aquí
// const { ... } = libro;
Ejercicio 2: Spread
Combina estos objetos y sobrescribe el precio:
const productoBase = { id: 1, nombre: 'Camiseta', precio: 20 };
const oferta = { precio: 15, descuento: '25%' };
// Resultado esperado: { id: 1, nombre: 'Camiseta', precio: 15, descuento: '25%' }
Ejercicio 3: Optional Chaining
Obtén el código postal SIN causar errores:
const cliente = {
nombre: 'Pedro',
direccion: {
calle: 'Gran Vía'
// codigoPostal no existe
}
};
// const cp = ...?
console.log(cp); // undefined (sin error)
Volver a JS
Volver a JS