Saltar al contenido
Curso de JavaScriptModerno · Interactivo

Unidad 7 · Lecciones 035-047

Objetos en JavaScript

Si tuvieras que elegir un solo tema de este curso para dominar, seria este. Un objeto agrupa en una sola variable toda la informacion de una cosa: un producto, un usuario, una cita. Casi todo lo que devuelve una base de datos o una API llega en forma de objeto.

📚 13 lecciones originales ⏱ Lectura ~40 min ↩ Requiere: Unidades 2 a 6

🎯 Objetivo de aprendizaje

Al terminar sabras crear objetos, leer y modificar sus valores, extraerlos con destructuring (incluso anidados), protegerlos con freeze y seal, unir dos objetos, anadirles funciones usando this y recorrer sus llaves y valores.

7.1 Crear un objeto

Imagina que quieres describir un producto. Sin objetos necesitas tres variables sueltas:

Sin objeto: variables sueltas
const nombre = 'Monitor de 20 pulgadas';
const precio = 300;
const disponible = true;
Con objeto: todo agrupado
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

console.log(producto);

La sintaxis, parte por parte

{ }
Las llaves delimitan el objeto. Si ves = {, es un objeto.
nombre
Se llama propiedad o llave (key). Es el identificador del dato.
:
Dentro de un objeto se asigna con dos puntos, no con =.
,
Cada par llave-valor se separa con coma. Nunca con punto y coma.

⚠ Los dos errores tipicos

  • Usar = en vez de : dentro del objeto.
  • Separar las propiedades con ; en vez de ,.

Esta forma de crear objetos se llama object literal. Hay otra, el object constructor, que veras en la seccion 7.10.

7.2 Acceder a los valores

Las dos sintaxis de acceso
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

// 1. Sintaxis de PUNTO: la habitual
console.log(producto.nombre);
console.log(producto.precio);
console.log(producto.disponible);

// 2. Sintaxis de CORCHETES: menos comun, pero util en algunos casos
console.log(producto['nombre']);

💡 Cuando usar los corchetes

La sintaxis de punto es la normal. Los corchetes son necesarios cuando el nombre de la propiedad esta guardado en una variable o contiene caracteres raros. Lo veras en accion con for...in en la Unidad 11.

7.3 Anadir y eliminar propiedades

Puedes anadir propiedades despues de crear el objeto, mientras el programa se ejecuta. La sintaxis es la misma de punto, pero ahora con = porque estas fuera de las llaves.

Anadir una propiedad nueva
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

// Fuera del objeto se usa = , no :
producto.imagen = 'imagen.jpg';

console.log(producto);
Eliminar una propiedad
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

delete producto.disponible;

console.log(producto);   // ya no aparece disponible

💡 Caso real

Cuando consultas un usuario en una base de datos, te devuelve el objeto completo, incluida su contrasena cifrada. Antes de enviar esos datos al navegador, se hace delete usuario.password. Es un uso cotidiano de delete.

7.4 Destructuring de objetos

Muy a menudo quieres sacar un valor del objeto y guardarlo en su propia variable. La forma antigua exige dos pasos:

La forma antigua
const nombre = producto.nombre;   // crear variable + extraer valor
console.log(nombre);

ECMAScript 6 introdujo el destructuring (extraer de una estructura), que hace las dos cosas en un solo paso:

Destructuring
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

// Las llaves a la IZQUIERDA del = indican destructuring
const { nombre } = producto;

console.log(nombre);

💡 Como reconocerlo

Cuando veas const { algo } = objeto, con llaves al lado izquierdo del igual, estas viendo destructuring. Es una senal inequivoca.

Extraer varios valores a la vez

Todo en una linea
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

const { nombre, precio, disponible } = producto;

console.log(nombre);
console.log(precio);
console.log(disponible);
Si la llave no existe
const producto = { nombre: 'Monitor', precio: 300 };

const { descuento } = producto;

console.log(descuento);   // undefined: la variable se crea, pero sin valor

+ Por que importa tanto

El curso original se regrabo entero en buena parte por el destructuring: cuando se grabo la primera version, muchas librerias y frameworks todavia no lo soportaban bien. Hoy es la forma estandar de trabajar con datos en React, Vue y practicamente cualquier proyecto moderno.

7.5 Objetos dentro de objetos

El valor de una propiedad puede ser otro objeto. Asi se construyen estructuras tan complejas como necesites:

Objeto anidado en varios niveles
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true,
    informacion: {
        medidas: {
            peso: '1kg',
            medida: '1m'
        },
        fabricacion: {
            pais: 'China'
        }
    }
};

console.log(producto);

Acceder a lo que hay dentro

Se encadenan puntos, un nivel por punto:

Bajando nivel a nivel
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    informacion: {
        medidas: { peso: '1kg', medida: '1m' },
        fabricacion: { pais: 'China' }
    }
};

console.log(producto.informacion);                        // el objeto entero
console.log(producto.informacion.medidas);                // un nivel mas
console.log(producto.informacion.medidas.peso);           // '1kg'
console.log(producto.informacion.fabricacion.pais);       // 'China'

✗ Si accedes a algo que no existe

producto.informacion.garantia.meses lanzara un error: JavaScript no puede leer la propiedad meses de algo que vale undefined. Es uno de los errores mas frecuentes al trabajar con datos de una API.

7.6 Destructuring de objetos anidados

Aqui la sintaxis se complica. La regla es: para bajar un nivel, se usan dos puntos y se abren llaves de nuevo.

Bajar un nivel
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    informacion: {
        medidas: { peso: '1kg', medida: '1m' },
        fabricacion: { pais: 'China' }
    }
};

// "Entra en informacion y saca fabricacion"
const { informacion: { fabricacion } } = producto;

console.log(fabricacion);   // { pais: 'China' }

⚠ El detalle que confunde a todo el mundo

En el ejemplo anterior, la variable informacion no se crea. Los dos puntos significan «entra aqui», no «crea esta variable». Si intentas hacer console.log(informacion) obtendras un error.

Crear tambien la variable intermedia

Extraer el nivel intermedio ademas del interior
const producto = {
    informacion: {
        medidas: { peso: '1kg' },
        fabricacion: { pais: 'China' }
    }
};

// Anadir "informacion," antes crea tambien esa variable
const { informacion, informacion: { fabricacion } } = producto;

console.log(informacion);   // el objeto completo
console.log(fabricacion);   // { pais: 'China' }

Bajar dos niveles

Hasta el fondo
const producto = {
    informacion: {
        fabricacion: { pais: 'China' }
    }
};

const { informacion: { fabricacion: { pais } } } = producto;

console.log(`Este articulo fue fabricado en ${pais}`);

💡 Como leerlo

Lee de fuera hacia dentro: «de producto, entra en informacion, dentro entra en fabricacion, y de ahi saca pais». Solo lo ultimo se convierte en variable.

7.7 El problema con const y los objetos

En la Unidad 2 aprendiste que una variable const no se puede reasignar. Con los objetos eso es cierto... a medias.

✗ Reasignar la variable: prohibido
const nombreProducto = 'Monitor';
nombreProducto = 'Tablet';
// TypeError: Assignment to
// constant variable
⚠ Modificar su contenido: permitido
const producto = {
    nombre: 'Monitor',
    precio: 300,
    disponible: true
};

producto.disponible = false;   // se permite
delete producto.precio;        // tambien

console.log(producto);

🎓 Pregunta de entrevista

¿Se pueden modificar los valores de una variable declarada con const?
Si, cuando es un objeto o un arreglo. const protege la referencia (no puedes apuntar la variable a otra cosa), pero no el contenido. Para proteger el contenido hay que usar Object.freeze() o Object.seal().

7.8 Proteger un objeto: freeze y seal

+ Primero: el modo estricto

Para que estos metodos avisen con un error en lugar de fallar en silencio, conviene activar el modo estricto escribiendo 'use strict'; en la primera linea del archivo. Es el equivalente del comparador === pero a nivel de documento: le dice a JavaScript «no me permitas malas practicas aqui».

Que impide el modo estricto
'use strict';

x = 20;            // Sin modo estricto: JavaScript crea la variable por ti
console.log(x);    // Con modo estricto: ReferenceError, x no esta definida

Object.freeze() — congelar

Deja el objeto tal cual esta: no se puede modificar, ni anadir, ni eliminar nada.

Congelar un objeto
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

Object.freeze(producto);

// Comprobar si esta congelado
console.log(Object.isFrozen(producto));   // true

// Con 'use strict' activo, cualquier intento de cambio lanza un error.
// Los envolvemos en try/catch para poder ver los tres mensajes seguidos.

try { producto.disponible = false; }
catch (e) { console.error('Modificar: ' + e.message); }

try { producto.imagen = 'nueva.jpg'; }
catch (e) { console.error('Anadir: ' + e.message); }

try { delete producto.precio; }
catch (e) { console.error('Eliminar: ' + e.message); }

console.log(producto);   // el objeto sigue exactamente igual

Object.seal() — sellar

Mas permisivo: si deja modificar las propiedades existentes, pero no anadir ni eliminar.

Sellar un objeto
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

Object.seal(producto);

console.log(Object.isSealed(producto));   // true

// SI funciona: la propiedad ya existia
producto.disponible = false;

// NO: no se pueden anadir propiedades nuevas
try { producto.imagen = 'nueva.jpg'; }
catch (e) { console.error('Anadir: ' + e.message); }

// NO: no se pueden eliminar
try { delete producto.precio; }
catch (e) { console.error('Eliminar: ' + e.message); }

console.log(producto);   // disponible ya es false, pero sigue teniendo precio

🎓 Pregunta de entrevista

ModificarAnadirEliminarComprobar con
Object.freeze()NoNoNoObject.isFrozen()
Object.seal()SiNoNoObject.isSealed()

7.9 Unir dos objetos

Tarea muy comun: tienes los datos de un cliente en un objeto y su direccion en otro, y necesitas combinarlos. Hay dos formas.

Forma 1: Object.assign()
const producto = { nombre: 'Monitor', precio: 300 };
const medidas  = { peso: '1kg', medida: '1m' };

const resultado = Object.assign(producto, medidas);

console.log(resultado);
Forma 2: spread operator (la moderna)
const producto = { nombre: 'Monitor', precio: 300 };
const medidas  = { peso: '1kg', medida: '1m' };

const resultado2 = { ...producto, ...medidas };

console.log(resultado2);

💡 Que significan los tres puntos

...producto quiere decir «toma una copia de todo lo que hay dentro de producto y colocalo aqui». Se llama spread operator (o rest operator segun donde aparezca). La primera vez resulta poco intuitivo, pero es la sintaxis mas usada hoy.

Lo volveras a ver con arreglos en las Unidades 8 y 12.

7.10 Funciones dentro de objetos y la palabra this

+ Nota sobre el orden

Las funciones se estudian en la Unidad 9. Aqui basta con saber que una funcion es un bloque de codigo que se ejecuta cuando lo llamas.

Una propiedad de un objeto puede tener como valor una funcion. Se le llama metodo:

El problema: sin this
const nombre = 'Hola';
const precio = 20;

const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    mostrarInfo: function() {
        console.log(`El producto ${nombre} tiene un precio de ${precio}`);
    }
};

producto.mostrarInfo();
// "El producto Hola tiene un precio de 20"
// Esta leyendo las variables de FUERA, no las del objeto
La solucion: this
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    mostrarInfo: function() {
        console.log(`El producto ${this.nombre} tiene un precio de ${this.precio}`);
    }
};

producto.mostrarInfo();
// "El producto Monitor de 20 pulgadas tiene un precio de 300"

💡 Que es this

this significa «este mismo objeto». Le dice a JavaScript que busque la propiedad dentro del objeto en vez de salir a buscarla fuera.

Por que es imprescindible

Con dos objetos distintos se ve claramente que this mantiene cada uno en su sitio:

Los valores no se mezclan
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    mostrarInfo: function() {
        console.log(`El producto ${this.nombre} tiene un precio de ${this.precio}`);
    }
};

const producto2 = {
    nombre: 'Tablet',
    precio: 3000,
    mostrarInfo: function() {
        console.log(`El producto ${this.nombre} tiene un precio de ${this.precio}`);
    }
};

producto.mostrarInfo();
producto2.mostrarInfo();

⚠ this es palabra reservada

No puedes nombrar una variable this. El lenguaje ya la usa.

7.11 El Object Constructor

El object literal te obliga a escribir el objeto entero cada vez. Si vas a crear muchos objetos del mismo tipo, es mejor tener una plantilla: eso es un object constructor.

Una plantilla para crear productos
// La plantilla: por convencion se nombra con mayuscula inicial
function Producto(nombre, precio) {
    this.nombre = nombre;
    this.precio = precio;
    this.disponible = true;   // valor por defecto
}

// Crear objetos a partir de ella con la palabra new
const producto2 = new Producto('Monitor de 24 pulgadas', 500);
const producto3 = new Producto('Television', 100);

console.log(producto2);
console.log(producto3);

Que hace cada parte

  • function Producto(nombre, precio) — define la plantilla y los datos que necesita.
  • this.nombre = nombre — guarda el valor recibido dentro del objeto que se esta creando. Sin this, los valores se perderian o se mezclarian.
  • new Producto(...) — crea un objeto nuevo a partir de la plantilla.

💡 Ya conocias esta sintaxis

new String(), new Number(), new Boolean()... es exactamente el mismo mecanismo. Con un constructor estas creando tu propio «tipo de dato».

+ Contexto

Esta era la forma de hacer programacion orientada a objetos en JavaScript antes de que el lenguaje incorporase las class. Aunque el constructor es mas dinamico, en el dia a dia se usa mucho mas el object literal. Conviene conocer ambos.

7.12 Object.keys, values y entries

Los tres metodos
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    precio: 300,
    disponible: true
};

// keys -> las LLAVES (la parte izquierda)
console.log(Object.keys(producto));

// values -> los VALORES (la parte derecha)
console.log(Object.values(producto));

// entries -> ambos en PARES
console.log(Object.entries(producto));
Object.keys()
Devuelve un arreglo con los nombres de las propiedades.
Object.values()
Devuelve un arreglo con los valores.
Object.entries()
Devuelve un arreglo de parejas [llave, valor].

El truco: saber si un objeto esta vacio

Comprobar si una consulta devolvio datos
const clienteEncontrado = { nombre: 'Ana', email: 'ana@correo.com' };
const clienteVacio = {};

console.log(Object.keys(clienteEncontrado));           // ['nombre', 'email']
console.log(Object.keys(clienteEncontrado).length);    // 2

console.log(Object.keys(clienteVacio));                // []
console.log(Object.keys(clienteVacio).length);         // 0  -> esta vacio

Es la forma habitual de comprobar si una consulta a la base de datos devolvio algo o no. Object.entries() volvera a aparecer en la Unidad 11 para recorrer objetos con for...of.

7.13 Ejercicios practicos

Ejercicio 1

Llega hasta el pais

Con el objeto anidado de la seccion 7.5, accede al pais de fabricacion de dos maneras distintas: con sintaxis de punto y con destructuring anidado.

Ver solucion
Solucion
const producto = {
    nombre: 'Monitor de 20 pulgadas',
    informacion: {
        medidas: { peso: '1kg', medida: '1m' },
        fabricacion: { pais: 'China' }
    }
};

// Con sintaxis de punto
console.log(producto.informacion.fabricacion.pais);

// Con destructuring anidado
const { informacion: { fabricacion: { pais } } } = producto;
console.log(pais);
Ejercicio 2

Ficha de cliente con metodo

Crea un objeto cliente con nombre, email y saldo. Anadele un metodo mostrarResumen() que imprima los tres datos usando this y un template string.

Ver solucion
Solucion
const cliente = {
    nombre: 'Ana Lopez',
    email: 'ana@correo.com',
    saldo: 1250.5,
    mostrarResumen: function() {
        console.log(`Cliente: ${this.nombre}`);
        console.log(`Contacto: ${this.email}`);
        console.log(`Saldo disponible: ${this.saldo}`);
    }
};

cliente.mostrarResumen();
Reto 1

Fusionar sin destruir

Tienes un objeto usuario y otro direccion. Combinalos en un tercer objeto usando el spread operator, y demuestra que el objeto usuario original no se ha modificado.

Ver solucion
Solucion
const usuario = { nombre: 'Ana', email: 'ana@correo.com' };
const direccion = { ciudad: 'Guadalajara', pais: 'Mexico' };

const completo = { ...usuario, ...direccion };

console.log('Combinado:', completo);
console.log('Original:', usuario);   // intacto: solo nombre y email

💡 Diferencia con Object.assign

Object.assign(usuario, direccion) si modifica el primer objeto, porque lo usa como destino. El spread operator crea uno nuevo y deja los originales en paz. Esa idea (no modificar los datos originales) es la base de la programacion funcional.

Reto 2

Catalogo con constructor

Crea un constructor Curso que reciba titulo, precio e instructor, y que anada automaticamente publicado: true. Genera tres cursos, congela el primero, intenta modificarlo y comprueba el resultado.

Ver solucion
Solucion
function Curso(titulo, precio, instructor) {
    this.titulo = titulo;
    this.precio = precio;
    this.instructor = instructor;
    this.publicado = true;
}

const curso1 = new Curso('JavaScript Moderno', 12, 'Juan');
const curso2 = new Curso('React desde cero', 15, 'Ana');
const curso3 = new Curso('Node.js avanzado', 18, 'Luis');

console.log(curso1);
console.log(curso2);
console.log(curso3);

// Congelar el primero
Object.freeze(curso1);
console.log('Congelado?', Object.isFrozen(curso1));

try { curso1.precio = 0; }
catch (e) { console.error('No se pudo cambiar: ' + e.message); }

console.log('Precio tras intentar cambiarlo:', curso1.precio);   // sigue 12

// Ver sus llaves y valores
console.log(Object.keys(curso1));
console.log(Object.values(curso1));

7.14 Resumen de lo aprendido

  • Un objeto agrupa varios datos de una misma cosa. Se crea con llaves, se asigna con : y se separa con ,.
  • Acceso: sintaxis de punto (producto.nombre) o de corchetes (producto['nombre']).
  • Modificar: fuera del objeto se usa =. Para borrar, delete objeto.propiedad.
  • Destructuring: const { nombre } = producto crea la variable y extrae el valor en un paso.
  • Anidado: los dos puntos bajan de nivel; solo la ultima llave se convierte en variable.
  • const no protege el contenido de un objeto: solo impide reasignar la variable.
  • Object.freeze() impide todo cambio; Object.seal() permite modificar lo existente pero no anadir ni borrar.
  • Unir objetos: Object.assign() (modifica el primero) o { ...a, ...b } (crea uno nuevo).
  • this dentro de un metodo se refiere al propio objeto; sin el, JavaScript busca las variables fuera.
  • El object constructor es una plantilla para crear muchos objetos iguales con new.
  • Object.keys/values/entries devuelven arreglos con las llaves, los valores o ambos.

7.15 Verificacion de cierre

¿Que permite Object.seal() que Object.freeze() no permite?

  • Anadir nuevas propiedades
  • Eliminar propiedades
  • Modificar las propiedades existentes
  • Nada, son identicos

Tras const { informacion: { fabricacion } } = producto;, ¿que variables existen?

  • Solo informacion
  • Solo fabricacion
  • Las dos
  • Ninguna: es sintaxis invalida

¿Para que sirve this dentro de un metodo de objeto?

  • Para que la propiedad se busque dentro del propio objeto
  • Para congelar el objeto y que no se modifique
  • Para convertir el objeto en un arreglo
  • Para crear una copia del objeto

🏁 Unidad completada