¿Que es prototipo en JavaScript y para que sirve?
Un prototipo en JavaScript es el mecanismo que permite que los objetos compartan propiedades y métodos entre sí. Entender qué es, para qué sirve y cómo funciona es fundamental para comprender la herencia y la reutilización de código en el lenguaje. En este tutorial veremos ejemplos prácticos para aplicarlo correctamente en proyectos reales y en el DOM.

Índice
1. ¿Qué es exactamente un prototipo en JavaScript?
Un prototipo en JavaScript es un objeto especial del cual otros objetos pueden heredar propiedades y métodos.
En JavaScript no existe la herencia clásica como en Java o C#. En su lugar, el lenguaje se basa en herencia prototípica.
Todo objeto en JavaScript tiene internamente una referencia a otro objeto.
👉 Ese otro objeto es su prototipo.
Cuando intentás acceder a una propiedad que no existe en el objeto, JavaScript la busca en su prototipo.
Si no la encuentra ahí, sigue buscando en el prototipo del prototipo… y así sucesivamente.
A eso se le llama:
🔗 Prototype Chain (cadena de prototipos)
1.1. Ejemplo de prototipo:
// 1. Creamos un objeto simple
const persona = {
saludar() {
return "Hola";
}
};
// 2. Creamos un objeto que HEREDA de persona, o sea, con Object.create hacemos que ahora persona sea prototipo de alumno
const alumno = Object.create(persona);
// 3. Ejecutamos el objeto alumno, pero llamamos a la función saludar() que está en persona
console.log(alumno.saludar()); // "Hola"Lenguaje del código: JavaScript (javascript)
¿Qué está pasando?
personatiene el métodosaludar.alumnoNO tiene ese método.- Pero
alumnofue creado conObject.create(persona)(entonces su prototipo espersona). - Cuando llamamos
alumno.saludar(), JavaScript:- Busca en
alumno❌ - No lo encuentra
- Va al prototipo (
persona) ✅ - Lo ejecuta
- Busca en
👉 Eso es herencia prototípica.
VISUALMENTE:
alumno
↓
persona
↓
Object.prototype
↓
nullLenguaje del código: JavaScript (javascript)
Esta sería la Prototype Chain (cadena de prototipos), donde como ya vimos persona es prototipo de alumno, pero….
📌¿QUÉ ES Object.prototype?
Es el prototipo base que tienen todos los objetos normales en JavaScript (recuerda que en JS todo es un objeto).
- Como vimos en este ejemplo, cuando llamamos a la propiedad de alumno y no la encontramos directamente ahí, Javascript accedió a su prototipo persona (que fue creado manualmente).
- Pero también podría suceder que quisiéramos usar otras funcionalidades nativas que nos da JavaScript, y aquí es donde podríamos hacer uso de los métodos que existen nativamente
Object.prototype.
¿Qué contiene Object.prototype? Algunos de lo métodos básicos que todos los objetos pueden usar:
persona.toString();
persona.hasOwnProperty("saludar");
persona.valueOf();Lenguaje del código: CSS (css)
Vos nunca los definiste.
Vienen de Object.prototype.
📌¿QUÉ SIGNIFICA null?
null significa: «Aquí termina la cadena de prototipos.» Es el punto final.
Entonces tu cadena completa sería:
alumno
↓
persona (creado manualmente por vos)
↓
Object.prototype (agregado automáticamente por JS)
↓
null (fin de la cadena)Lenguaje del código: JavaScript (javascript)
1.2.. Prototipos y el DOM (Lo que ves en el navegador)
Esto no es solo teoría; el DOM vive de esto. Cuando seleccionás un botón, ese objeto tiene métodos porque hereda de prototipos superiores.
Supongamos que seleccionás un botón:
const boton = document.querySelector("button");Lenguaje del código: JavaScript (javascript)
Visualmente, la cadena prototípica sería algo así:
boton
↓
HTMLButtonElement.prototype
↓
HTMLElement.prototype
↓
Element.prototype
↓
Node.prototype
↓
EventTarget.prototype
↓
Object.prototype
↓
nullLenguaje del código: CSS (css)
¿Qué significa esto?
Cada nivel le agrega capacidades al botón.
- HTMLButtonElement
- Métodos y propiedades específicas del botón
- (Ej:
form,type, etc.)
- HTMLElement
- Propiedades comunes a elementos HTML
- (Ej:
innerHTML,style,classList)
- Element
- Métodos generales de elementos
- (Ej:
querySelector,getAttribute)
- Node
- Propiedades estructurales del DOM
- (Ej:
parentNode,childNodes)
- EventTarget
- Capacidad de manejar eventos
- (Ej:
addEventListener,removeEventListener)
- Object.prototype
- Métodos básicos de todos los objetos
- (Ej:
toString,hasOwnProperty)
Esta cadena la podríamos visualizar por ejemplo si desde la consola de la herramienta inspeccionar hacemos lo siguiente:
const boton = document.querySelector('button');
// ¿De dónde sale .addEventListener?
// No está en el botón, está en el prototipo EventTarget.
console.log(boton.__proto__); // HTMLButtonElement
console.log(boton.__proto__.__proto__); // HTMLElement
console.log(boton.__proto__.__proto__.__proto__); // Element
console.log(boton.__proto__.__proto__.__proto__.__proto__); // Node
console.log(boton.__proto__.__proto__.__proto__.__proto__.__proto__); // EventTargetLenguaje del código: JavaScript (javascript)
¿Por qué es la base del lenguaje?
Porque permite la reutilización de código dinámica. Podés añadir un método a un prototipo en tiempo de ejecución y automáticamente todos los objetos que heredan de él (incluso los que ya fueron creados) tendrán acceso a ese nuevo método.
NOTA!! Recordá que prototype es una propiedad que solo tienen las funciones, mientras que __proto__ es el enlace que tienen los objetos creados para mirar hacia su padre.
2. ¿Para que sirve el prototipo en JavaScript?
Los prototipos sirven principalmente para tres cosas críticas en el desarrollo: eficiencia de memoria, herencia y extensibilidad.
Aquí te explico cada una:
2.1. Ahorro masivo de memoria (Reutilización)
Esta es la función más importante. Sin prototipos, si crearas 1,000 objetos (por ejemplo, 1,000 enemigos en un juego o 1,000 filas en una tabla de datos), cada uno tendría su propia copia de los métodos.
- SIN prototipo: 1,000 objetos $\times$ 5 métodos = 5,000 funciones en RAM.
- CON prototipo: 1,000 objetos $\times$ 0 métodos propios + 5 métodos en el prototipo = ¡Solo 5 funciones en RAM!
2.2. Crear una jerarquía (Herencia)
Sirve para que un objeto «hijo» pueda usar las capacidades de un «padre». Esto es lo que permite que el lenguaje sea estructurado.
Ejemplo práctico:
Imaginate que tenés un objeto genérico Usuario. Todos los usuarios pueden iniciarSesion(). Pero luego tenés un Admin. El Admin es un Usuario, pero con superpoderes.
const usuarioBase = {
conectado: false,
conectar() { this.conectado = true; console.log("Sesión iniciada"); }
};
const admin = Object.create(usuarioBase); // El prototipo de admin ahora es usuarioBase
admin.borrarBaseDeDatos = function() { console.log("¡Boom! Datos borrados"); };
admin.conectar(); // Funciona, porque lo hereda del prototipo.
admin.borrarBaseDeDatos(); // Funciona, es propio.
usuarioBase.conectar(); //Aquí usuarioBase no tiene acceso a admin y así limitamos sus capacidadesLenguaje del código: JavaScript (javascript)
2.3. Extender el lenguaje (Polyfills y Plugins)
¿Alguna vez te preguntaste por qué todos los Arrays tienen el método .map() o .filter()? Es porque están en el prototipo global de Array.
Si JavaScript no tuviera un método que necesitás, vos podrías «enseñarle» a todos los strings del mundo a hacer algo nuevo (aunque esto debe hacerse con cuidado):
// Le enseñamos a todos los textos a saludar
String.prototype.saludar = function() {
return `¡Hola, soy el texto: ${this.toUpperCase()}!`;
};
console.log("javascript".saludar()); // "¡Hola, soy el texto: JAVASCRIPT!"Lenguaje del código: JavaScript (javascript)
¿Qué está pasando en este ejemplo?:
1️⃣ Modificamos el prototipo de los strings:
String.prototype.saludar = ...Lenguaje del código: JavaScript (javascript)
Estás agregando un nuevo método al prototipo global de todos los strings.
Eso significa que cualquier texto ahora puede usar .saludar().
2️⃣ Cuando llamás:
"javascript".saludar()Lenguaje del código: JavaScript (javascript)
JavaScript hace esto internamente:
- El string no tiene
saludardirectamente. - Entonces lo busca en
String.prototype. - Lo encuentra.
- Lo ejecuta.
NOTA!! Modificar prototipos nativos (String.prototype, Array.prototype, etc.) no es buena práctica en producción. Se usa para aprendizaje o polyfills controlados.
Veamos la utilidad de prototipo en el DOM:
En tu día a día con el DOM, el prototipo sirve para que cualquier elemento que selecciones (un div, un p, un input) tenga automáticamente métodos como appendChild(), addEventListener() o classList. No tenés que programarlos cada vez; ya vienen «de fábrica» en la cadena de prototipos de los nodos de HTML.
En pocas palabras: El prototipo sirve para que los objetos no tengan que «cargar» con todo el código, sino que sepan a quién preguntarle cuando necesitan hacer algo.
3. El enlace [[Prototype]] y diferencia entre __proto__ y Object.getPrototypeOf().
3.1. ¿Qué es realmente [[Prototype]]?
[[Prototype]] es un enlace interno invisible del motor de JavaScript.
- No es una propiedad normal.
- No se puede acceder directamente.
- Es parte de la especificación del lenguaje.
Cada objeto tiene internamente algo como:
obj.[[Prototype]] → otroObjetoLenguaje del código: CSS (css)
Ese enlace es el que permite la herencia.
3.2. ¿Qué es __proto__?
__proto__ es un accesor (getter/setter) que permite ver o modificar el [[Prototype]].
Ejemplo:
const animal = { tipo: "mamífero" };
const perro = {};
perro.__proto__ = animal;
console.log(perro.tipo); // "mamífero"Lenguaje del código: JavaScript (javascript)
Aquí:
perro.[[Prototype]] = animal
Pero usando __proto__.
¿PROBLEMA?
__proto__:
- Es legado
- No es la forma recomendada
- Puede afectar rendimiento
3.3. ¿Qué es Object.getPrototypeOf()?
Es el método moderno y estándar para leer el prototipo.
Ejemplo:
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype);
// trueLenguaje del código: JavaScript (javascript)
Esto devuelve exactamente el valor interno de [[Prototype]].
🔎¿Y para modificarlo correctamente?
Se usa:
Object.setPrototypeOf(obj, nuevoPrototipo);Lenguaje del código: JavaScript (javascript)
Ejemplo:
const animal = { especie: "mamífero" };
const perro = {};
Object.setPrototypeOf(perro, animal);
console.log(perro.especie); // "mamífero"Lenguaje del código: JavaScript (javascript)
3.4. Diferencia clara entre los tres
| Concepto | Qué es | Uso recomendado |
|---|---|---|
[[Prototype]] |
Enlace interno real del motor. | No accesible. |
__proto__ |
Accesor público legado. | ❌ Evitar. |
Object.getPrototypeOf() |
Método estándar para leer prototipo. | ✅ Sí. |
Object.setPrototypeOf() |
Método estándar para modificar. | ⚠️ Usar con cuidado. |
NOTA IMPORTANTE:
Cambiar el prototipo dinámicamente con:
Object.setPrototypeOf()Lenguaje del código: JavaScript (javascript)
Puede romper optimizaciones del motor.
Por eso lo ideal es:
- Definir el prototipo al momento de crear el objeto.
- Usar
Object.create().
