Command Palette

Search for a command to run...

Tipos de Referencia y Objetos en JavaScript

Entiende la diferencia fundamental entre tipos primitivos y de referencia. Aprende cómo funcionan las referencias en memoria, cómo copiar objetos correctamente y evitar bugs comunes.

Lectura: 11 min
Nivel: Principiante

TL;DR - Resumen rápido

  • Primitivos se copian por valor, objetos se copian por referencia
  • Objetos son colecciones de pares clave-valor. Arrays, funciones y fechas también son objetos
  • Dos variables pueden apuntar al mismo objeto en memoria - cambios en una afectan la otra
  • Spread (...) y Object.assign() hacen copias shallow (superficiales) - objetos anidados siguen siendo referencias
  • Para copias deep (profundas) usa structuredClone() o JSON.parse(JSON.stringify())
  • Object.keys(), Object.values(), Object.entries() retornan arrays de las propiedades del objeto
  • Comparar objetos con === compara referencias, no contenido - {} === {} es siempre false

Primitivos vs Tipos de Referencia

JavaScript tiene dos categorías fundamentales de tipos: primitivos y de referencia. Los tipos primitivos (string, number, boolean, null, undefined, symbol, bigint) se copian por valor - cuando asignas una variable primitiva a otra, copias el valor. Los tipos de referencia (objetos, arrays, funciones) se copian por referencia - cuando asignas un objeto a otra variable, ambas apuntan al mismo objeto en memoria.

Esta diferencia es crítica y causa muchos bugs en desarrolladores que están aprendiendo. Con primitivos, cada variable tiene su propia copia independiente del valor. Con objetos, múltiples variables pueden referenciar el mismo objeto, por lo que modificar el objeto a través de una variable afecta a todas las demás que lo referencian.

primitivos-vs-referencia.js
Loading code...

El ejemplo demuestra claramente la diferencia. Con el primitivo, cambiar num2 no afecta num1 porque cada variable tiene su propia copia del valor. Con el objeto, cambiar obj2.name también cambia obj1.name porque ambas variables apuntan al mismo objeto en memoria. No hay dos objetos separados - hay un solo objeto con dos referencias a él.

¿Qué son Tipos de Referencia?

Cuando creas un objeto, JavaScript almacena el objeto en memoria y la variable guarda la "dirección" (referencia) a esa ubicación en memoria, no el objeto en sí. Por eso asignar obj2 = obj1 no crea un nuevo objeto - copia la referencia, haciendo que ambas variables apunten a la misma ubicación de memoria.

¿Qué son los Objetos?

Los objetos en JavaScript son colecciones de pares clave-valor, donde cada clave (también llamada propiedad) es un string o Symbol, y el valor puede ser cualquier tipo de dato: primitivos, otros objetos, arrays, funciones. Los objetos son la estructura de datos fundamental de JavaScript - arrays, funciones, fechas, expresiones regulares, y prácticamente todo excepto primitivos, son objetos bajo el capó.

objeto-basico.js
Loading code...

Los objetos literales se crean con llaves . Las propiedades pueden contener cualquier valor: primitivos, arrays, otros objetos, o funciones (llamadas métodos cuando están dentro de un objeto). Puedes anidar objetos infinitamente, crear propiedades dinámicamente, y JavaScript es extremadamente flexible con la estructura de objetos.

Todo (Casi) es un Objeto

En JavaScript, casi todo es un objeto o se comporta como uno. Arrays son objetos con propiedades numéricas, funciones son objetos invocables, fechas son objetos con métodos de tiempo. Incluso los primitivos tienen "object wrappers" que les permiten tener métodos como "hello".toUpperCase(). Esta uniformidad hace JavaScript flexible pero requiere entender objetos profundamente.

Crear Objetos: Diferentes Formas

Hay varias formas de crear objetos en JavaScript. La más común es la notación literal con llaves. También puedes usar el constructor Object(), Object.create(), o clases (que son azúcar sintáctica sobre funciones constructoras). Para la mayoría de casos, la notación literal es la forma más clara y directa.

crear-objetos.js
Loading code...

La notación literal es la forma preferida por su claridad y brevedad. Object.create() es útil cuando necesitas control sobre la cadena de prototipos. new Object() funciona pero es innecesario - hace lo mismo más concisamente. Puedes usar propiedades computadas con corchetes para nombres de propiedades dinámicos, y la sintaxis abreviada cuando la propiedad tiene el mismo nombre que la variable.

Acceder y Modificar Propiedades

Hay dos formas de acceder a propiedades de objetos: notación de punto (objeto.propiedad) y notación de corchetes (objeto['propiedad']). La notación de punto es más común y legible, pero los corchetes son necesarios cuando el nombre de la propiedad es dinámico, contiene espacios, o empieza con número.

acceder-propiedades.js
Loading code...

La notación de punto funciona cuando conoces el nombre de la propiedad en tiempo de escritura. Los corchetes permiten nombres dinámicos - útil cuando iteras propiedades o cuando el nombre viene de una variable. Puedes agregar propiedades nuevas simplemente asignándolas, y eliminar propiedades con el operador delete. El operador in verifica si una propiedad existe.

Propiedades Inexistentes

Acceder a una propiedad que no existe retorna undefined, no un error. Esto puede causar bugs sutiles - user.address.city causará error si address no existe (cannot read property 'city' of undefined). Usa optional chaining (?.) para seguridad: user?.address?.city retorna undefined si cualquier parte de la cadena no existe.

Referencias en Memoria: El Concepto Clave

Entender cómo funcionan las referencias es absolutamente crucial en JavaScript. Cuando asignas un objeto a una variable, la variable no contiene el objeto en sí - contiene una referencia (puntero) a la ubicación del objeto en memoria. Múltiples variables pueden tener referencias al mismo objeto, y modificar el objeto a través de cualquier referencia afecta a todas las demás.

referencias-memoria.js
Loading code...

Este comportamiento es intencional y útil - permite pasar objetos grandes a funciones sin copiar toda la data. Pero puede causar bugs si no lo entiendes. Cuando pasas un objeto a una función, la función puede modificar el objeto original. Cuando guardas un objeto en un array, el array guarda la referencia, no una copia. Este es el origen de muchos bugs en código JavaScript.

Mutabilidad Accidental

Un error común es pensar que const protege el contenido de objetos. const user = previene reasignar user, pero NO previene modificar user.name o user.age. Para objetos verdaderamente inmutables, usa Object.freeze(), pero es shallow - solo congela el primer nivel de propiedades.

Copiar Objetos: Shallow vs Deep Copy

Copiar objetos correctamente es un desafío común. Hay dos tipos de copias: shallow (superficial) y deep (profunda). Una copia shallow copia el primer nivel de propiedades, pero propiedades que son objetos siguen siendo referencias al original. Una copia deep copia recursivamente todos los niveles, creando objetos completamente independientes.

copiar-objetos.js
Loading code...

El spread operator (...) y Object.assign() son las formas más comunes de hacer copias shallow. Funcionan bien para objetos planos (sin anidación). Para copias deep, structuredClone() es la solución moderna (disponible desde 2022 en navegadores modernos). JSON.parse(JSON.stringify()) funciona pero tiene limitaciones: no copia funciones, undefined, Symbols, o valores especiales como NaN.

Cuándo Usar Qué Tipo de Copia

Usa shallow copy cuando: (1) El objeto es plano sin anidación, (2) Sabes que no modificarás objetos anidados, (3) Rendimiento es crítico. Usa deep copy cuando: (1) El objeto tiene múltiples niveles de anidación, (2) Necesitas independencia total del original, (3) Trabajas con datos de usuario que se modificarán.

Métodos Útiles del Objeto Object

JavaScript proporciona varios métodos estáticos en Object para trabajar con objetos. Los más útiles son Object.keys() (obtiene array de claves), Object.values() (array de valores), Object.entries() (array de pares [clave, valor]), Object.freeze() (congela objeto), y Object.seal() (sella objeto permitiendo modificar propiedades existentes pero no agregar/eliminar).

metodos-object.js
Loading code...

Object.keys(), values(), y entries() son esenciales para iterar objetos. Object.freeze() hace un objeto inmutable (shallow), útil para constantes. Object.seal() previene agregar/eliminar propiedades pero permite modificar las existentes. hasOwn() (o hasOwnProperty()) verifica si una propiedad pertenece al objeto directamente, no a su prototipo.

Iterar Objetos Correctamente

Para iterar objetos, usa Object.keys(obj).forEach() o for...of con Object.entries(). Evita for...in sin verificar hasOwnProperty() porque itera propiedades heredadas del prototipo. Los métodos modernos Object.keys/values/entries solo retornan propiedades propias del objeto, no heredadas.

Errores Comunes con Objetos

Los errores más comunes con objetos vienen de no entender referencias: comparar objetos con === (compara referencias, no contenido), modificar objetos sin querer (por referencias compartidas), copiar superficialmente cuando necesitas copia profunda, y asumir que const hace objetos inmutables.

errores-comunes.js
Loading code...

El error más común es comparar objetos con ===, esperando que compare contenido - solo compara si son el mismo objeto en memoria. Para comparar contenido, usa JSON.stringify() para objetos simples o bibliotecas como Lodash para casos complejos. Modificar parámetros de función afecta el original porque se pasa la referencia. const no protege propiedades del objeto, solo la reasignación de la variable.

Resumen: Tipos de Referencia y Objetos

Conceptos clave:

  • Primitivos se copian por valor, objetos por referencia
  • Múltiples variables pueden apuntar al mismo objeto en memoria
  • Comparar con === compara referencias, no contenido del objeto
  • Spread (...) hace copia shallow - objetos anidados siguen siendo referencias
  • structuredClone() crea copias deep (profundas) completamente independientes

Mejores prácticas:

  • Usa notación literal {} para crear objetos en lugar de new Object()
  • Copia objetos explícitamente con spread o structuredClone() según necesidad
  • Usa Object.keys/values/entries para iterar objetos de forma segura
  • Recuerda: const previene reasignación, no mutación de propiedades