Function.prototype en JavaScript

Function.prototype es el objeto maestro del que heredan todas las funciones en JavaScript. Actúa como un almacén central que les otorga sus métodos esenciales, como call(), apply() y bind(), garantizando que cada función tenga acceso a las mismas capacidades básicas del lenguaje.

function.prototype en javascript

1. ¿Qué es Function.prototype?

Function.prototype es el objeto del cual heredan todas las funciones en JavaScript.

Es decir:

  • Toda función que creás está conectada internamente a Function.prototype.
  • Gracias a eso, todas las funciones tienen métodos como call, apply y bind.
  • A su vez, Function.prototype hereda de Object.prototype (El ancestro final de casi todo en JS).

1.1. Ejemplo:

Supongamos que tenemos esta función:

function saludar() {
  console.log("Hola");
}Lenguaje del código: JavaScript (javascript)

Ahora verificamos su PROTOTIPO:

console.log(Object.getPrototypeOf(saludar) === Function.prototype); 
// trueLenguaje del código: JavaScript (javascript)

Entonces, su cadena prototípica quedaría así:

saludar
   ↓
Function.prototype
   ↓
Object.prototype
   ↓
nullLenguaje del código: JavaScript (javascript)

Y esto significa que todas las funciones tienen como prototipo padre a Function.prototype, permitiéndole heredar sus métodos automáticamente sin necesidad de haberlos creados con anterioridad.

1.2. Entonces… ¿qué contiene Function.prototype?

Contiene métodos que TODAS las funciones pueden usar.

Por ejemplo:

console.log(typeof Function.prototype.call);   // function
console.log(typeof Function.prototype.apply);  // function
console.log(typeof Function.prototype.bind);   // functionLenguaje del código: JavaScript (javascript)

1.2.1. Ejemplo práctico con call()

// Creamos la función
function presentar() {
  console.log("Soy " + this.nombre);
}

// Creamos un objeto plano que no tiene ninguna función dentro.
const persona = { nombre: "Juan" };

// Ejecutamooss la funcionn
presentar.call(persona);Lenguaje del código: JavaScript (javascript)

Salida:

Soy Juan

🔹¿Qué hace call()?

Cuando ejecutas .call(persona), le estás diciendo a la función: «Ejecútate, pero por favor, haz que la palabra reservada this dentro de ti apunte al objeto persona«.

  • Sin .call(): this.nombre sería undefined (o daría error), porque this apuntaría al objeto global.
  • Con .call(): this.nombre se convierte en "Juan".

🔹¿Por qué funciona call() si nunca la escribimos en la función?

Si tú miras el código de tu función presentar, tú nunca escribiste el método .call. Entonces, ¿cómo es que puedes usarlo?

El camino de búsqueda de JavaScript:

  1. Busca en la instancia: El motor de JS busca la propiedad call dentro de la función presentar. No la encuentra.
  2. Sube al prototipo: Como presentar es una función, JS mira en su «ADN»: Function.prototype.
  3. Encuentra el tesoro: En Function.prototype vive el método call(). JS lo toma «prestado» de ahí y lo ejecuta.

Porque:

presentar
   ↓
Function.prototypeLenguaje del código: JavaScript (javascript)

Y call() vive dentro de Function.prototype, entonces presentar hereda de él.

2. Constructor.prototype y diferencia con Function.prototype.

2.1. ¿Qué es Constructor.prototype?

Es un objeto que existe dentro de cualquier función que tú definas. Su único propósito es servir de depósito de métodos para los objetos que crees con la palabra new (Funciones Constructoras).

  • ¿Quién lo usa? Los «hijos» (instancias).

2.1.1 Ejemplo

// El Constructor (El molde físico)
function Animal(nombre) {
  this.nombre = nombre;
}

// Lo que el constructor "les da a sus hijos"
Animal.prototype.hablar = function() {
  console.log("Soy " + this.nombre);
};

// Creamos los "hijos" (instancias)
const perro = new Animal("Firulais");
const gato = new Animal("Michi");

perro.hablar(); // Soy Firulais
gato.hablar();  // Soy MichiLenguaje del código: JavaScript (javascript)

¿Qué está pasando aquí?

Cuando hacés:

const perro = new Animal("Firulais");Lenguaje del código: JavaScript (javascript)

JavaScript hace esto internamente:

  1. Crea un objeto vacío {}
  2. Lo conecta con Animal.prototype
  3. Ejecuta la función usando ese objeto como this
  4. Devuelve el objeto

La cadena queda así:

perro
   ↓
Animal.prototype
   ↓
Object.prototype
   ↓
nullLenguaje del código: JavaScript (javascript)

¿Dónde vive el método hablar?

No vive dentro de perro.

Comprobalo:

console.log(perro.hasOwnProperty("hablar")); 
// falseLenguaje del código: JavaScript (javascript)

El método vive en:

Animal.prototypeLenguaje del código: CSS (css)

Pero como perro está conectado a ese objeto, puede usarlo.

💡 Entonces… Cuando decimos:

Constructor.prototype es lo que la función da a sus hijos

Significa:

  • Todo lo que pongas en Animal.prototype
  • Será compartido por todas las instancias creadas con new Animal()

Es como un manual compartido.

🔥 Si agregamos 100 animales:

const a1 = new Animal("A1");
const a2 = new Animal("A2");
const a3 = new Animal("A3");Lenguaje del código: JavaScript (javascript)

Todos comparten el mismo método hablar. No se copia 100 veces en memoria.

2.2. Casos comunes donde usamos Constructor.prototype.

En el día a día como desarrollador, no siempre escribes Constructor.prototype directamente (especialmente ahora que usamos la palabra clave class), pero todo lo que ocurre por debajo sigue usando este concepto.

Aquí te presento los 4 casos más comunes donde este «baúl de regalos» es el protagonista:

2.2.1. Compartir métodos (El caso de «Ahorro de Memoria»)

Es el uso más clásico. Si tienes miles de objetos, no quieres que cada uno cargue con sus propias funciones.

  • Ejemplo: En un videojuego, tienes 100 enemigos. Todos caminan igual. En lugar de que cada enemigo tenga su propia función caminar, la pones en el prototipo.
  • Beneficio: Los 100 enemigos usan la misma función en memoria.
function Enemigo(tipo) {
    this.tipo = tipo;
    this.vida = 100;
}

// Caso común: Todos los enemigos comparten la lógica de recibir daño
Enemigo.prototype.recibirDanio = function(puntos) {
    this.vida -= puntos;
    console.log(`${this.tipo} ahora tiene ${this.vida} de vida.`);
};Lenguaje del código: JavaScript (javascript)

2.2.2. Polyfills (Arreglar navegadores viejos)

Este es un caso histórico y muy importante. Cuando un navegador viejo no tiene una función moderna (como .includes() de los arreglos), los programadores usan el prototipo para «enseñarle» esa función.

  • Cómo funciona: Acceden a Array.prototype (el constructor de todos los arrays) y le agregan el método que falta.
// Si el navegador no sabe qué es "saludar" para los arrays...
if (!Array.prototype.saludar) {
    Array.prototype.saludar = function() {
        console.log("¡Hola, soy un arreglo!");
    };
}

[1, 2, 3].saludar(); // Ahora todos los arreglos del mundo pueden saludarLenguaje del código: JavaScript (javascript)

2.2.3. Extender funcionalidades de librerías

Muchas librerías antiguas (como jQuery) o sistemas de plugins funcionan permitiéndote agregar cosas a su prototipo. Si quieres que todos los objetos de una librería tengan una herramienta nueva creada por ti, la inyectas en su prototype.

2.2.4. Herencia entre «Clases» (Antes de ES6)

Antes de que existiera la palabra class en 2015, la única forma de hacer que un Gato heredara de un Animal era conectando sus prototipos.

  • Cómo se hacía: Se decía que el prototipo del hijo era una copia del prototipo del padre.
function Animal() {}
Animal.prototype.comer = function() { console.log("Comiendo..."); };

function Gato() {}
// Caso común: Herencia manual
Gato.prototype = Object.create(Animal.prototype); 

const miGato = new Gato();
miGato.comer(); // Heredado de AnimalLenguaje del código: JavaScript (javascript)

🚨¿Por qué ya no vemos tanto la palabra .prototype en el código moderno?

Porque en el JavaScript actual usamos Clases. Pero ¡ojo!, esto es lo que quiero que grabes como programador:

class Programador {
    constructor(nombre) {
        this.nombre = nombre;
    }
    saludar() { console.log("Hola"); }
}Lenguaje del código: JavaScript (javascript)

Aunque no veas la palabra, JavaScript por detrás agarra el método saludar y lo mete automáticamente en Programador.prototype. Las clases son solo una forma más bonita («azúcar sintáctico») de escribir prototipos.

Resumen de casos:

  1. Optimizar memoria (Métodos compartidos).
  2. Parchear el lenguaje (Polyfills).
  3. Crear plugins (Extender librerías).
  4. Conectar objetos (Herencia).

2.3. Diferencia principal entre Constructor.prototype y Function.prototype.

🔵 Constructor.prototype afecta a las INSTANCIAS.
🟢 Function.prototype afecta a las FUNCIONES.

Esa es la diferencia central. Ahora lo vemos claro con ejemplo.

🔵 Constructor.prototype

Es el objeto que heredan los objetos creados con new.

Ejemplo:

function Persona(nombre) {
  this.nombre = nombre;
}

Persona.prototype.saludar = function() {
  console.log("Hola, soy " + this.nombre);
};

const p1 = new Persona("Juan");

p1.saludar();Lenguaje del código: JavaScript (javascript)

Cadena:

p1
  ↓
Persona.prototype
  ↓
Object.prototype
  ↓
nullLenguaje del código: JavaScript (javascript)

Todo lo que pongas en Persona.prototype lo reciben las instancias.

🟢 Function.prototype

Es el objeto del cual heredan todas las funciones.

Ejemplo:

function saludar() {}

console.log(Object.getPrototypeOf(saludar) === Function.prototype);
// trueLenguaje del código: JavaScript (javascript)

Cadena:

saludar
   ↓
Function.prototype
   ↓
Object.prototype
   ↓
nullLenguaje del código: JavaScript (javascript)

Gracias a eso, todas las funciones tienen:

saludar.call()
saludar.apply()
saludar.bind()Lenguaje del código: CSS (css)

Porque esos métodos viven en:

Function.prototypeLenguaje del código: JavaScript (javascript)

🔥 Comparación directa. Supongamos:

function Robot() {}
const r1 = new Robot();Lenguaje del código: JavaScript (javascript)

Tenemos DOS cadenas distintas:

⛓️‍💥Cadena de la función:

Robot
  ↓
Function.prototypeLenguaje del código: JavaScript (javascript)

⛓️‍💥Cadena de la instancia:

r1Robot.prototypeLenguaje del código: CSS (css)

Son mundos distintos.

4. ¿Cómo puedo comprobar en la consola que una función hereda de Function.prototype?

Aquí tienes las tres formas de comprobarlo, desde la más común hasta la más técnica.

4.1. Las 3 formas de comprobarlo en consola:

Supongamos que tenemos una función sencilla:

function miFuncion() {}Lenguaje del código: JavaScript (javascript)

A. Usando Object.getPrototypeOf() (La más profesional)

Es la forma estándar y moderna de preguntarle a JavaScript: «¿Quién es el padre de este elemento?».

console.log(Object.getPrototypeOf(miFuncion) === Function.prototype); 
// Resultado: trueLenguaje del código: JavaScript (javascript)

B. Usando la propiedad __proto__ (La más rápida)

Aunque es una propiedad «informal», todos los navegadores la soportan para inspección rápida.

console.log(miFuncion.__proto__ === Function.prototype); 
// Resultado: trueLenguaje del código: JavaScript (javascript)

C. Usando instanceof

Preguntas si la función es una «instancia» del constructor global Function.

console.log(miFuncion instanceof Function); 
// Resultado: trueLenguaje del código: JavaScript (javascript)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *