Command Palette

Search for a command to run...

Herencia Prototípica: La Cadena de Prototipos en JavaScript

Entiende cómo funciona la cadena de prototipos que permite a los objetos heredar propiedades y métodos de otros objetos.

Lectura: 18 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • La herencia prototípica usa una cadena de prototipos para compartir comportamiento
  • Las funciones constructoras crean objetos con el operador new
  • El operador new establece automáticamente el prototipo del objeto
  • La propiedad constructor apunta a la función constructora del objeto
  • Object.create() permite crear objetos con un prototipo específico
  • JavaScript busca propiedades en la cadena de prototipos automáticamente

Introducción a la Herencia Prototípica

La herencia prototípica es el mecanismo que JavaScript usa para permitir que los objetos hereden propiedades y métodos de otros objetos. A diferencia de lenguajes como Java o C++ que usan herencia de clases, JavaScript usa una cadena de prototipos para compartir comportamiento.

Este mecanismo es fundamental para entender cómo funciona JavaScript internamente. Cuando creas un objeto usando new Object() o literales de objeto, JavaScript automáticamente establece una conexión entre el objeto y Object.prototype. Esta conexión permite que el objeto acceda a propiedades y métodos que no tiene definidos.

Diferencia con clases ES6

ES6 introdujo la palabra clave class para crear clases con una sintaxis más familiar a programadores de otros lenguajes. Sin embargo, bajo el capó, las clases de ES6 son azúcar sintáctico que se compilan a herencia prototípica.

¿Cómo Funciona?

Para entender la herencia prototípica, necesitas comprender tres conceptos clave: la propiedad interna __proto__, la cadena de prototipos, y cómo JavaScript busca propiedades.

  • <strong>__proto__</strong>: Cada objeto tiene una propiedad oculta que apunta a su prototipo
  • <strong>Object.prototype</strong>: Es el prototipo de todos los objetos creados con new Object() o literales
  • <strong>Cadena de prototipos</strong>: __proto__ de un objeto apunta al __proto__ de su prototipo, y así sucesivamente
  • <strong>Búsqueda de propiedades</strong>: JavaScript busca en el objeto, luego en __proto__, luego en el prototipo del prototipo
como-funciona.js
Loading code...

En este ejemplo, creamos un objeto padre y un objeto hijo. El objeto hijo no tiene el método saludar(), pero cuando lo llamamos, JavaScript lo encuentra en el prototipo del padre y lo ejecuta correctamente.

Búsqueda automática

Esta búsqueda automática en la cadena de prototipos es lo que hace que la herencia funcione sin que tengas que configurar explícitamente las relaciones entre objetos.

La Cadena de Prototipos

La cadena de prototipos es una serie de enlaces que conectan los objetos entre sí a través de sus prototipos. Cuando accedes a una propiedad de un objeto, JavaScript recorre esta cadena buscando la propiedad.

cadena-prototipos.js
Loading code...

En este ejemplo, creamos tres objetos: abuelo, padre y nieto. Cada objeto hereda del anterior, creando una cadena de prototipos. El objeto nieto puede acceder a métodos definidos en el abuelo a través de esta cadena.

Object.getPrototypeOf()

Puedes usar Object.getPrototypeOf() para obtener el prototipo de cualquier objeto. Esto es útil para depurar y entender las relaciones de herencia en tu código.

Constructor Functions y new

Las funciones constructoras son la forma tradicional y más común de implementar herencia prototípica en JavaScript. Una función constructora es simplemente una función regular que se invoca con el operador new para crear objetos con un prototipo específico.

constructor-functions.js
Loading code...

Este ejemplo muestra cómo crear una función constructora Persona y agregar métodos a su prototype. Cuando usas new Persona(), JavaScript crea un nuevo objeto, establece su prototipo a Persona.prototype, ejecuta la función con this apuntando al nuevo objeto, y retorna el objeto resultante.

¿Qué hace el operador new?

El operador new realiza cuatro pasos automáticamente: crea un objeto vacío, asigna el prototipo del objeto al prototype de la función constructora, ejecuta la función con this apuntando al nuevo objeto, y retorna el objeto creado. Este proceso es la base de la herencia prototípica con funciones constructoras.

Olvidar new causa errores

Si olvidas usar new al llamar una función constructora, this apuntará al objeto global (window en navegadores) en lugar de crear un nuevo objeto. Esto puede causar bugs difíciles de detectar.

  • <strong>Paso 1:</strong> Crea un nuevo objeto vacío {}
  • <strong>Paso 2:</strong> Asigna el prototipo: nuevoObjeto.__proto__ = Constructor.prototype
  • <strong>Paso 3:</strong> Ejecuta la función con this apuntando al nuevo objeto
  • <strong>Paso 4:</strong> Retorna el nuevo objeto (a menos que la función retorne otro objeto explícitamente)

La Propiedad constructor

Cada objeto en JavaScript tiene acceso a una propiedad llamada constructor que apunta a la función constructora que lo creó. Esta propiedad se hereda del prototype de la función constructora y es útil para identificar el tipo de un objeto o crear nuevas instancias del mismo tipo.

propiedad-constructor.js
Loading code...

En este ejemplo vemos cómo la propiedad constructor apunta a la función Persona. Puedes usar esta propiedad para crear nuevas instancias sin tener acceso directo a la función constructora. Sin embargo, si sobrescribes el prototype de una función, debes restaurar manualmente la propiedad constructor.

Restaurar constructor

Cuando sobrescribes completamente el prototype de una función (en lugar de agregar propiedades), siempre incluye constructor: FuncionConstructora para mantener la referencia correcta.

Ejemplo Práctico

Un caso de uso común de la herencia prototípica es agregar métodos a Object.prototype. Esto permite que todos los objetos creados tengan acceso a esos métodos, lo cual es muy útil para extender la funcionalidad del lenguaje.

ejemplo-practico.js
Loading code...

En este ejemplo, agregamos un método saludar() a Object.prototype. Ahora cualquier objeto, incluidos los que ya existen, pueden usar este método. Esto demuestra cómo la herencia prototípica permite compartir código entre objetos.

Ventaja de la herencia prototípica

Una ventaja clave de la herencia prototípica es que los métodos agregados a Object.prototype están disponibles para todos los objetos sin que tengas que heredarlos explícitamente. Esto es más eficiente en términos de memoria.

Object.create()

Object.create() es un método que te permite crear un nuevo objeto con un prototipo específico. Esto te da control total sobre la cadena de herencia del nuevo objeto, en lugar de heredar de Object.prototype por defecto.

object-create.js
Loading code...

En este ejemplo, usamos Object.create() para crear un objeto con un prototipo personalizado. El objeto ana hereda de persona, y persona a su vez hereda de Object.prototype. Esto crea una cadena: ana → persona → Object.prototype → null. También puedes crear objetos sin prototipo usando Object.create(null), útil para diccionarios puros.

Consideraciones de rendimiento

Object.create() puede ser más lento que crear objetos con new Object() o literales en algunos casos. Úsalo cuando necesitas un control preciso sobre la cadena de prototipos del nuevo objeto.

Modificar el Prototipo

Aunque no es una práctica común, puedes modificar el prototipo de un objeto después de que ha sido creado. Esto te permite cambiar dinámicamente la herencia de un objeto en tiempo de ejecución.

modificar-prototipo.js
Loading code...

En este ejemplo, creamos un objeto con un prototipo inicial y luego lo cambiamos a Object.prototype. Los métodos agregados antes del cambio siguen disponibles para objetos creados con el prototipo anterior, mientras que los nuevos objetos usan el prototipo actualizado.

Advertencia importante

Modificar prototipos de objetos existentes puede causar comportamiento inesperado en tu aplicación. Úsalo con precaución y documenta claramente cualquier modificación dinámica de prototipos.

Resumen: Herencia Prototípica

Conceptos principales:

  • La herencia prototípica usa cadenas de prototipos
  • Funciones constructoras crean objetos con new
  • El operador new establece el prototipo automáticamente
  • La propiedad constructor apunta a la función constructora
  • Object.create() crea objetos con prototipo específico
  • JavaScript busca propiedades en la cadena de prototipos

Mejores prácticas:

  • Usa funciones constructoras para crear objetos similares
  • Agrega métodos al prototype, no al constructor
  • Restaura constructor al sobrescribir prototype
  • Usa Object.getPrototypeOf() en lugar de __proto__
  • Evita modificar prototipos con setPrototypeOf()
  • Usa Object.create(null) para diccionarios puros