Skip to content

Lección 48: Prototype y Cadena de Prototipos

JavaScript es un lenguaje basado en prototipos. Cada objeto tiene una propiedad interna [[Prototype]] que apunta a otro objeto. Cuando accedes a una propiedad, JS la busca en el objeto, y si no la encuentra, sigue por la cadena de prototipos.

const objeto = { a: 1 };
console.log(objeto.toString); // función — viene del prototipo Object
console.log(objeto.a); // 1 — propia del objeto

Cuando llamas a objeto.toString(), JS:

  1. Busca toString en el objeto → no está
  2. Busca en objeto.__proto__ (Object.prototype) → lo encuentra
const persona = { nombre: 'Ana' };
// Forma antigua (no recomendada)
console.log(persona.__proto__);
// Forma moderna (recomendada)
console.log(Object.getPrototypeOf(persona)); // Object.prototype
// Verificar si una propiedad es del prototipo
console.log(persona.hasOwnProperty('nombre')); // true
console.log(persona.hasOwnProperty('toString')); // false
// Añadir métodos al prototipo de clases nativas
String.prototype.capitalizar = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
console.log('hola mundo'.capitalizar()); // "Hola mundo"
Array.prototype.primero = function() {
return this[0];
};
Array.prototype.ultimo = function() {
return this[this.length - 1];
};
const nums = [1, 2, 3, 4, 5];
console.log(nums.primero()); // 1
console.log(nums.ultimo()); // 5
// ¡Pero ten cuidado! Modificar prototipos nativos puede causar conflictos
// Herencia prototípica con Object.create()
const animal = {
respirar() {
return 'Respirando';
},
mover() {
return 'Moviéndose';
}
};
const perro = Object.create(animal);
perro.ladrar = function() {
return 'Guau!';
};
console.log(perro.ladrar()); // "Guau!" (propio)
console.log(perro.respirar()); // "Respirando" (heredado)
console.log(perro.mover()); // "Moviéndose" (heredado)
console.log(Object.getPrototypeOf(perro) === animal); // true

Modificar el prototipo de tipos nativos (String, Array, Object) está mal visto en producción, especialmente en proyectos con múltiples librerías. Si todos modifican String.prototype, habrá conflictos.

// ❌ Evita esto en proyectos compartidos
Object.prototype.saludar = function() { return 'Hola'; };
const obj = {};
console.log(obj.saludar()); // "Hola" — pero contamina todos los objetos
// ✅ En su lugar, usa funciones auxiliares o clases

La cadena termina en null. Object.prototype.__proto__ es null.

Entender el prototipo es clave para dominar JavaScript:

  • Las clases (ES6) usan prototipos por debajo
  • Los métodos de instancia de una clase viven en el prototipo, no en cada instancia
  • instanceof recorre la cadena de prototipos para verificar
  • El patrón delegación (Object.create) es más flexible que la herencia clásica
// Los métodos de clase están en el prototipo
class Ejemplo {
metodo() {}
}
const instancia = new Ejemplo();
console.log(instancia.hasOwnProperty('metodo')); // false
console.log(Ejemplo.prototype.hasOwnProperty('metodo')); // true

Usando Object.create(), crea una cadena de prototipos de 3 niveles:

  • vehiculo con método conducir()
  • coche (hereda de vehiculo) con método abrirPuertas()
  • miCoche (hereda de coche) con propiedad marca

Verifica que miCoche tenga acceso a todos los métodos.

const vehiculo = {
conducir() {
return 'Conduciendo...';
}
};
// Crea coche que herede de vehiculo
// Crea miCoche que herede de coche
const miCoche = Object.create(coche);
miCoche.marca = 'Toyota';
console.log(miCoche.marca); // "Toyota"
console.log(miCoche.abrirPuertas()); // ¿?
console.log(miCoche.conducir()); // ¿?