¿Qué es la cadena de prototipos en JavaScript?

Como JavaScript resuelve propiedades a traves de [[Prototype]], que diferencia prototype de __proto__ y donde termina la cadena.

En JavaScript, cada objeto tiene una referencia interna llamada [[Prototype]] que apunta a otro objeto (o a null). Cuando accedes a una propiedad, el motor primero la busca en el objeto. Si no la encuentra, sigue por [[Prototype]] y repite el proceso hasta llegar a null. A esa secuencia se le llama cadena de prototipos y es el mecanismo nativo de herencia del lenguaje.

Como funciona la busqueda

Lookup a traves de la cadena

javascript
const animal = {
  respirar() {
    return 'respirando';
  },
};

const perro = Object.create(animal);
perro.ladrar = () => 'guau';

perro.ladrar();    // 'guau'        -> esta en perro
perro.respirar();  // 'respirando'  -> heredado desde animal
perro.volar;       // undefined     -> no esta en ninguno

El motor recorre perro -> animal -> Object.prototype -> null. Cuando el lookup llega a null sin encontrar la propiedad, devuelve undefined.

prototype vs __proto__

Dos nombres que se confunden a menudo:

  • __proto__ (o mejor, Object.getPrototypeOf(obj)): es la referencia real de un objeto a su prototipo. Existe en todas las instancias.
  • prototype: es una propiedad que solo tienen las funciones. Define que objeto se asignara como [[Prototype]] de las instancias creadas con new.

prototype vs __proto__

javascript
function Usuario(nombre) {
  this.nombre = nombre;
}

Usuario.prototype.saludar = function () {
  return `Hola, ${this.nombre}`;
};

const ada = new Usuario('Ada');

Object.getPrototypeOf(ada) === Usuario.prototype; // true
ada.saludar(); // 'Hola, Ada' -> resuelto via prototype chain

Final de la cadena

Casi todos los objetos terminan su cadena en Object.prototype, cuyo [[Prototype]] es null.

Recorrer la cadena

javascript
const obj = {};

Object.getPrototypeOf(obj) === Object.prototype;            // true
Object.getPrototypeOf(Object.prototype);                    // null

Puedes crear objetos sin prototipo si quieres un diccionario “limpio” sin metodos heredados:

Objeto sin prototipo

javascript
const diccionario = Object.create(null);
diccionario.clave = 'valor';

diccionario.hasOwnProperty; // undefined  -> no hereda nada

Puntos clave

  • La herencia en JavaScript es prototipal, no clasica: los objetos heredan de otros objetos.
  • Las clases ES6 son azucar sintactico sobre la cadena de prototipos.
  • Modificar Object.prototype o Array.prototype afecta a todos los objetos del programa: evitalo en codigo de produccion.
  • Cuanto mas larga la cadena, mas pasos hace cada lookup: relevante en hot paths.

Referencias