Nivel inicial17 min de lectura · Publicado el

¿Qué es un objeto en JavaScript? Explicado con ejemplos

Qué es un objeto en JavaScript: una cajonera con las claves nombre, edad y lenguajes; persona.nombre abre su cajón y sale "Ada". Cada clave guarda su valorrubentejera.com "Ada"nombreedadlenguajespersona.nombre→ "Ada"
Como una cajonera con etiquetas: cada cajón lleva una clave (nombre, edad, lenguajes) y guarda dentro su valor. persona.nombre abre el cajón nombre y devuelve "Ada".

Un objeto en JavaScript es un conjunto de pares clave/valor: una forma de agrupar bajo un mismo nombre datos que van juntos, como el nombre, la edad y los lenguajes de una persona. En otros lenguajes lo llamarás diccionario, hash o array asociativo.

Piensa en una cajonera con etiquetas: cada cajón tiene un nombre (la clave) y dentro guarda algo (el valor). Puedes tener tantos cajones como quieras, abrir cualquiera por su nombre, añadir uno nuevo o quitarlo.

Los objetos en JavaScript están por todas partes: un usuario que llega de una API, la configuración de una librería o el propio console con el que escribes en la terminal. Si entiendes cómo funcionan, entiendes buena parte del lenguaje.

Cómo se crea un objeto

La forma más directa es escribirlo entre llaves. Esto se llama literal de objeto:

const persona = {
  nombre: "Ada",
  edad: 36,
  lenguajes: ["JavaScript", "Python"],
  direccion: { ciudad: "Madrid" },
  saludar() {
    return `Hola, soy ${this.nombre}`;
  },
};

Cada par clave: valor es una propiedad. Los valores pueden ser de cualquier tipo: textos, números, arrays, otros objetos o funciones. Una propiedad que guarda una función, como saludar, se llama método; lo vemos a fondo más abajo.

Primitivos y objetos: los dos grandes tipos de datos

Para entender qué es un objeto ayuda saber qué no lo es. JavaScript tiene siete tipos primitivos:

Primitivo Ejemplo typeof
String (texto) "Ada" "string"
Number (número) 36 "number"
BigInt (entero muy grande) 10n "bigint"
Boolean true "boolean"
Undefined undefined "undefined"
Symbol Symbol("id") "symbol"
Null null "object" (un error histórico)

Todo lo demás es un objeto. La diferencia práctica es que un primitivo es un valor fijo, como un número escrito en un papel, mientras que un objeto es un contenedor que puedes ir cambiando, como la cajonera.

const texto = "Ada";
console.log(texto.toUpperCase(), texto.length); // ADA 3

try {
  texto.apellido = "Lovelace";
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}
// TypeError: Cannot create property 'apellido' on string 'Ada'

Un texto parece tener métodos (toUpperCase) y propiedades (length), pero no es un objeto: cuando le pides una propiedad, JavaScript lo envuelve un instante en un objeto String, lo usa y lo descarta. Por eso no puedes guardarle una propiedad nueva. En un módulo (un fichero que se carga con import y export) o en modo estricto (una versión más exigente del lenguaje, que se activa con "use strict" y que los módulos usan siempre) lanza un error; en un script clásico sin modo estricto, la propiedad se pierde en silencio y leerla da undefined.

Tipos de objetos en JavaScript

Además de los objetos que escribes entre llaves, el lenguaje trae muchos ya hechos. Todos son objetos, aunque cada uno tenga su especialidad:

Objeto Para qué sirve typeof
{} Agrupar datos con nombre "object"
Array Listas ordenadas "object"
Date Fechas y horas "object"
Map y Set Colecciones de claves o de valores únicos "object"
Function Código que se puede llamar "function"
RegExp Expresiones regulares "object"
Error Errores que se lanzan con throw "object"
console.log(typeof {}, typeof [], typeof new Date(), typeof new Map());
// object object object object
console.log(typeof function () {}); // function

console.log([] instanceof Object, new Date() instanceof Object, (() => {}) instanceof Object);
// true true true

typeof dice "function" para las funciones, pero instanceof Object confirma que también son objetos: objetos que, además, se pueden llamar. Para los arrays, typeof no ayuda; usa Array.isArray(). Tienes sus métodos en Métodos de arrays en JavaScript.

Cómo leer una propiedad: punto o corchetes

console.log(persona.nombre);           // Ada
console.log(persona["edad"]);          // 36
console.log(persona.direccion.ciudad); // Madrid
console.log(persona.saludar());        // Hola, soy Ada

Las dos formas leen lo mismo. ¿Cuándo usar cada una?

Forma Cuándo
persona.nombre Casi siempre: conoces el nombre de la clave al escribir el código
persona["nombre"] Cuando la clave está en una variable o tiene espacios o guiones
const campo = "edad";
console.log(persona[campo]);                    // 36

console.log(persona.telefono);                  // undefined
console.log(persona.direccion?.codigoPostal);   // undefined

Si la clave no existe, obtienes undefined, no un error. El operador ?. (encadenamiento opcional) evita el error cuando lo que puede faltar es un objeto intermedio: si direccion no existiera, devolvería undefined en lugar de romper.

Añadir, cambiar y borrar propiedades

const coche = { marca: "Seat" };

coche.color = "rojo";      // añade
coche.marca = "Cupra";     // cambia
delete coche.color;        // borra

console.log(coche);                        // { marca: 'Cupra' }
console.log("marca" in coche);             // true
console.log(Object.hasOwn(coche, "color")); // false

Para saber si una propiedad existe, Object.hasOwn(objeto, clave) es la forma recomendada hoy, por encima del antiguo objeto.hasOwnProperty(clave).

¿Qué puede ser una clave?

Las claves son textos (strings) o símbolos (Symbol). Si usas otra cosa, como un número, JavaScript la convierte en texto:

const raro = { "nombre completo": "Ada Lovelace", 1: "uno" };
console.log(raro["nombre completo"]); // Ada Lovelace
console.log(Object.keys(raro));       // [ '1', 'nombre completo' ]

Fíjate en que la clave 1 sale como '1', entre comillas: es un texto.

Métodos: funciones dentro de un objeto (y this)

Un método es una función guardada en una propiedad. Sirve para que el objeto no solo guarde datos, sino que también sepa hacer cosas con ellos. Dentro del método, this es el objeto que lo llama:

const contador = {
  valor: 0,
  sumar() {
    this.valor += 1;
    return this.valor;
  },
};

console.log(contador.sumar()); // 1
console.log(contador.sumar()); // 2

La regla que conviene recordar: this lo decide quien llama, no dónde se escribió el método. En contador.sumar(), lo que hay a la izquierda del punto es contador, y eso es this. Es como la palabra «yo»: no significa siempre la misma persona, sino quien la dice.

Por eso, si sacas el método del objeto y lo llamas suelto, pierde su this:

const persona = {
  nombre: "Ada",
  saludar() {
    return `Hola, soy ${this.nombre}`;
  },
};

const otra = { nombre: "Grace", saludar: persona.saludar };
console.log(otra.saludar()); // Hola, soy Grace

const suelto = persona.saludar;
try {
  suelto();
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}
// TypeError: Cannot read properties of undefined (reading 'nombre')

const atado = persona.saludar.bind(persona);
console.log(atado()); // Hola, soy Ada

El mismo método dice «Grace» cuando lo llama otra. Llamado suelto, en un módulo (o en modo estricto) this es undefined y falla; en un script clásico sin modo estricto, this sería el objeto global y obtendrías "Hola, soy undefined". Pasa mucho al entregar un método como callback, por ejemplo a setTimeout o a un evento. bind crea una copia de la función con el this fijado.

Las funciones flecha no tienen this propio

Una función flecha (=>) no tiene this propio: usa el del sitio donde se escribió. Como método es mala idea (en arrow functions en JavaScript están los demás casos), pero dentro de un método es justo lo que quieres:

const equipo = {
  nombre: "Backend",
  miembros: ["Ada", "Grace"],
  presentar() {
    return this.miembros.map((miembro) => `${miembro} (${this.nombre})`);
  },
};

console.log(equipo.presentar()); // [ 'Ada (Backend)', 'Grace (Backend)' ]

La flecha que recibe map usa el this de presentar, que es equipo. Con una función normal en su lugar, this volvería a perderse. Hay una explicación más larga en This en JavaScript, Carlos Blé.

Recorrer un objeto: Object.keys, values y entries

const persona = { nombre: "Ada", edad: 36, ciudad: "Madrid" };

console.log(Object.keys(persona));
// [ 'nombre', 'edad', 'ciudad' ]
console.log(Object.values(persona));
// [ 'Ada', 36, 'Madrid' ]
console.log(Object.entries(persona));
// [ [ 'nombre', 'Ada' ], [ 'edad', 36 ], [ 'ciudad', 'Madrid' ] ]

for (const [clave, valor] of Object.entries(persona)) {
  console.log(`${clave}: ${valor}`);
}
// nombre: Ada
// edad: 36
// ciudad: Madrid

Object.entries es la más útil para recorrerlo: te da cada clave con su valor.

Desestructuración y spread: sacar y combinar propiedades

La desestructuración saca propiedades a variables en una sola línea. Puedes renombrarlas y darles un valor por defecto:

const { nombre, edad: años, pais = "España" } = persona;
console.log(nombre, años, pais); // Ada 36 España

El operador spread (...) vuelca las propiedades de un objeto dentro de otro nuevo. Es la forma habitual de crear una versión modificada sin tocar el original:

const actualizada = { ...persona, edad: 37 };
console.log(actualizada); // { nombre: 'Ada', edad: 37, ciudad: 'Madrid' }
console.log(persona.edad); // 36

Y un atajo: si la variable se llama igual que la clave, no hace falta repetirla.

const nombre2 = "Grace";
console.log({ nombre2 }); // { nombre2: 'Grace' }

Tienes más ejemplos en Asignación por destructuring en JavaScript.

Lo más importante: la variable guarda una referencia

Con los primitivos, al asignar una variable a otra se copia el valor. Quedan independientes:

let numero1 = 3.14159;
let numero2 = numero1;
numero2 = 42;
console.log(numero1, numero2); // 3.14159 42

Con los objetos no ocurre lo mismo. La variable no guarda el objeto, sino una referencia a él: algo así como la dirección de una casa. Si copias la dirección en otro papel, sigue habiendo una sola casa. Si alguien pinta la puerta, lo verás vayas con el papel que vayas.

const objeto1 = { a: 3.14159 };
const objeto2 = objeto1;   // copia la dirección, no la casa
objeto2.a = 42;

console.log(objeto1.a, objeto2.a); // 42 42
console.log(objeto1 === objeto2);  // true
Primitivos frente a objetos. Con primitivos se copia el valor: numero1 vale 3.14159 y numero2, 42, cada una con su copia. Con objetos se copia la referencia: objeto1 y objeto2 apuntan al mismo objeto { a: 42 } en memoria, y objeto1 === objeto2 da true.
Arriba, cada variable guarda su propio valor. Abajo, las dos variables guardan la misma dirección: por eso, al cambiar objeto2.a, también cambia objeto1.a.
Copiar la variable no copia el objeto.

Por la misma razón, dos objetos con el mismo contenido no son iguales para ===: son dos casas distintas, aunque estén amuebladas igual.

console.log({ a: 1 } === { a: 1 }); // false

Está explicado con más detalle en Diferencias entre == y === en JavaScript.

¿Por valor o por referencia?

Se suele decir que los objetos «se pasan por referencia», pero no es del todo exacto. JavaScript siempre copia el valor de la variable; en un objeto, ese valor es la referencia. Por eso una función puede modificar el objeto que recibe, pero no sustituirlo:

function cumplirAños(p) { p.edad += 1; }        // cambia la casa
function reemplazar(p) { p = { edad: 0 }; }     // solo cambia su papel

const ada = { edad: 36 };
cumplirAños(ada);
console.log(ada.edad); // 37
reemplazar(ada);
console.log(ada.edad); // 37

Más ejemplos en Paso por referencia y paso por valor en JavaScript.

¿Y si necesitas una copia?

Si quieres una casa nueva y no otra copia de la dirección, tienes dos opciones:

  • { ...obj } hace una copia superficial: copia el primer nivel, pero los objetos de dentro siguen compartidos.
  • structuredClone(obj) hace una copia profunda: copia todos los niveles. No admite funciones y no conserva la clase.
const original = { nombre: "Ada", direccion: { ciudad: "Madrid" } };

const superficial = { ...original };
superficial.direccion.ciudad = "Sevilla";
console.log(original.direccion.ciudad); // Sevilla

const profunda = structuredClone(original);
profunda.direccion.ciudad = "Bilbao";
console.log(original.direccion.ciudad); // Sevilla

Con spread, cambiar la ciudad de la copia cambia la del original, porque direccion era la misma casa. Con structuredClone, no. Las diferencias, los límites de cada forma y el truco antiguo de JSON.parse(JSON.stringify(obj)) están en cómo clonar un objeto en JavaScript.

Congelar un objeto: Object.freeze

Si const no impide cambiar las propiedades, ¿cómo se protege un objeto? Con Object.freeze:

"use strict";
const config = Object.freeze({ idioma: "es", tema: { color: "oscuro" } });

try {
  config.idioma = "en";
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}
// TypeError: Cannot assign to read only property 'idioma' of object '#<Object>'

config.tema.color = "claro";
console.log(config); // { idioma: 'es', tema: { color: 'claro' } }
console.log(Object.isFrozen(config), Object.isFrozen(config.tema)); // true false

Dos detalles. En modo estricto (y en los módulos, que siempre lo son), cambiar un objeto congelado lanza un error; sin modo estricto, el cambio se ignora en silencio. Y freeze es superficial: congela el primer nivel, no los objetos de dentro. Es como cerrar con llave la cajonera, pero no las cajas que hay dentro de cada cajón.

Objetos y JSON

JSON es el formato de texto con el que viajan los datos entre un servidor y una web, y se parece mucho a un literal de objeto. JSON.stringify convierte un objeto en texto y JSON.parse hace el camino contrario:

const persona = {
  nombre: "Ada",
  edad: 36,
  alta: new Date("2026-11-08T10:00:00Z"),
  apodo: undefined,
  saludar() { return "Hola"; },
};

const texto = JSON.stringify(persona);
console.log(texto);
// {"nombre":"Ada","edad":36,"alta":"2026-11-08T10:00:00.000Z"}

const deVuelta = JSON.parse(texto);
console.log(typeof deVuelta.alta, deVuelta.saludar); // string undefined

Fíjate en lo que se pierde por el camino: el método y la propiedad con undefined desaparecen, y la fecha vuelve como texto. JSON guarda datos, no comportamiento.

Objeto o Map: cuándo usar cada uno

Map también guarda pares clave/valor, así que es normal dudar. La documentación de MDN los compara en detalle; lo esencial:

Objeto {} Map
Tipos de clave Textos y símbolos Cualquier valor, también objetos
Tamaño Object.keys(o).length m.size
Claves heredadas Sí, del prototipo (toString…) Solo las que añades
Pasar a JSON Directo Hay que convertirlo
Muchas altas y bajas No está optimizado Mejor rendimiento
const visitas = new Map();
const usuario = { nombre: "Ada" };
visitas.set(usuario, 3);
console.log(visitas.get(usuario), visitas.size); // 3 1

const comoObjeto = {};
comoObjeto[usuario] = 3;
console.log(Object.keys(comoObjeto)); // [ '[object Object]' ]

Con un objeto como clave, el objeto normal la convierte en el texto '[object Object]', y cualquier otro objeto acabaría en el mismo cajón. Como regla práctica: un objeto para describir una cosa con campos conocidos (una persona, una configuración); un Map para una colección que crece y mengua, o cuando las claves no son textos.

Clases: una forma de fabricar objetos

Si necesitas muchos objetos con la misma forma y los mismos métodos, una clase hace de molde:

class Persona {
  constructor(nombre) {
    this.nombre = nombre;
  }
  saludar() {
    return `Hola, soy ${this.nombre}`;
  }
}

const ada = new Persona("Ada");
console.log(ada.saludar());   // Hola, soy Ada
console.log(typeof Persona);  // function
console.log(Object.keys(ada)); // [ 'nombre' ]

Las clases de JavaScript se construyen sobre prototipos: cada objeto tiene un «objeto padre» al que pregunta cuando no encuentra una propiedad. saludar no se copia en cada persona, sino que vive en Persona.prototype y todas lo comparten:

console.log(Object.getPrototypeOf(ada) === Persona.prototype); // true
console.log(Object.hasOwn(ada, "saludar"));                    // false

Por eso a menudo se dice que las clases son «azúcar sintáctico» sobre los prototipos. Es una buena primera idea, aunque no del todo exacta: las clases añaden reglas propias, como no poder llamarlas sin new o tener campos privados con #. Si quieres ir más allá, tienes la sintaxis completa (métodos, static, campos privados y herencia) en clases en JavaScript y cómo diseñarlas bien en Clases en código limpio.

Errores típicos con objetos

const persona = { nombre: "Ada" };

try {
  console.log(persona.direccion.ciudad);
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}
// TypeError: Cannot read properties of undefined (reading 'ciudad')
console.log(persona.direccion?.ciudad); // undefined

const clave = "nombre";
console.log(persona.clave, persona[clave]); // undefined Ada

const ajustes = { volumen: 0 };
console.log(ajustes.volumen || 50, ajustes.volumen ?? 50); // 50 0

console.log(`${persona}`); // [object Object]
  1. Leer dentro de algo que no existe. persona.direccion.ciudad falla si falta direccion. Usa ?. cuando un dato puede no venir.
  2. Usar el punto con una variable. persona.clave busca una propiedad llamada literalmente clave. Con una variable, corchetes: persona[clave].
  3. Dar un valor por defecto con ||. Trata 0, "" y false como si faltaran: el volumen 0 se convierte en 50. ?? solo actúa con null y undefined.
  4. Meter un objeto en un texto. Sale [object Object]. Para verlo, console.log(persona) o JSON.stringify(persona).
  5. Creer que const b = a copia el objeto, o que === compara el contenido. Las dos cosas trabajan con la referencia.
  6. Sacar un método y perder this. Al pasarlo como callback, envuélvelo en una flecha (() => persona.saludar()) o usa bind.

Tu chuleta

Quiero… Código
Crear un objeto const o = { clave: valor }
Leer una propiedad o.clave o o["clave"]
Leer sin romper si falta algo o.a?.b
Añadir o cambiar o.clave = valor
Borrar delete o.clave
Saber si existe Object.hasOwn(o, "clave")
Recorrerlo for (const [k, v] of Object.entries(o))
Sacar propiedades a variables const { clave } = o
Copia superficial { ...o }
Copia profunda structuredClone(o)
Que no se pueda cambiar Object.freeze(o)
Pasarlo a texto JSON JSON.stringify(o)

Fuentes

Comprobado el 8 de noviembre de 2026 en MDN Web Docs:

Todos los ejemplos se han ejecutado con Node.js 24.21.0 en Linux, como módulos ES, y las salidas mostradas son las reales.