Prototipos nativos en JavaScript

Comprender los prototipos nativos es dominar el ADN de JavaScript. Estos «planos maestros» permiten que arrays, objetos y elementos del DOM compartan potentes métodos y propiedades de forma eficiente, optimizando el rendimiento de tus aplicaciones mediante una cadena de herencia única y dinámica.

Prototipos nativos en JavaScript

1. ¿Qué son los prototipos nativos?

Los prototipos nativos en JavaScript (ver que es un prototipo) son los objetos prototipo que ya vienen incorporados dentro del lenguaje.

Permiten que todos los objetos creados a partir de tipos como Array, String, Object, Function, etc., hereden automáticamente propiedades y métodos.

En otras palabras:

  • JavaScript trae objetos base ya definidos
  • Cada uno tiene un prototype
  • Todos los valores creados a partir de ellos comparten ese prototype.

1.1. Ejemplo práctico con el prototipo de un Array

Veamos qué sucede «bajo el capó» cuando manipulas datos que vas a insertar en el DOM:

// 1. Creamos una instancia de Array
const tareas = ["Comprar pan", "Estudiar JS"];

// 2. Accedemos a un método nativo
// 'tareas' NO tiene el método .push() propio, lo hereda de Array.prototype
tareas.push("Limpiar casa");

// 3. Verificación de la herencia
console.log(Object.getPrototypeOf(tareas) === Array.prototype); // true

// 4. ¿De dónde viene .toString()? 
// Viene de más arriba: Object.prototype
console.log(tareas.toString()); Lenguaje del código: JavaScript (javascript)

Explicación del código:

  1. Instancia:
    • El array tareas es un objeto real en memoria (recuerda que en JS todo es un objeto).
  2. Herencia directa:
    • Al llamar a .push(), el motor de JS primero busca en tareas
    • Como no lo encuentra ahora busca en su prototipo Array.prototype.
    • Como lo encuentra ahí, lo ejecuta usando los datos de tareas.
  3. Herencia superior:
    • Y cuando llamamos a toString(), JS no lo encuentra en el objeto tareas ni en Array.prototype
    • Entonces, sube un nivel más hasta Object.prototype.
    • Lo encuentra aqui y lo ejecuta.

👉¿Qué sucede realmente en este ejemplo?

Cuando intentas usar un método, JavaScript busca en el objeto mismo. Si no lo encuentra, sube un peldaño al prototipo padre. Si no está ahí, sube al siguiente hasta llegar a Object.prototype (el ancestro común de todos).

🎯A ESTO SE LE LLAMA herencia prototípica.

Ahora bien, si queremos visualizar el camino que sigue JavaScript para ver hacia dónde se dirige para buscar estos métodos en sus prototipos superiores podríamos crear su cadena:

tareas
   ↓
Array.prototype
   ↓
Object.prototype
   ↓
nullLenguaje del código: JavaScript (javascript)

🎯 ESTA SERÍA LA cadena prototípica. y si volvemos a la explicación del ejemplo anterior, vemos como push() fue encontrada en array.prototype, y toString() en object.prototype.

¿Y QUÉ PASA CON null)

Efectivamente, null es el último eslabón de la cadena. Es el muro donde termina la búsqueda. Si intentamos ejecutar un método inexistente como .noExisto(), el motor de JavaScript hace este recorrido:

  1. En el Array (Tareas): Busca .noExisto(). No está.
  2. En Array.prototype: Sube y busca. No está.
  3. En Object.prototype: Sube al «abuelo» y busca. No está.
  4. En null: Llega al final. Como null no es un objeto, la búsqueda se detiene.

Aquí JavaScript que nos devuelve – ¿undefined o Error?

Aquí es donde debemos precisar:

  • Si intentas acceder a una propiedad que no existe (ej: tareas.noExisto), JavaScript te devuelve undefined.
  • Pero si intentas ejecutar esa propiedad como una función o método (ej: tareas.noExisto()), JavaScript no devuelve undefined, sino que lanza un error críticoTypeError: tareas.noExisto is not a function.

2. Principales prototipos nativos:

2.1. Object.prototype (El Patriarca)

Es la base de casi todo en JavaScript. Si un objeto no tiene algo, finalmente lo buscará aquí.

  • Qué contiene: Métodos de utilidad universal.
  • Métodos clave: hasOwnProperty(), toString(), valueOf(), isPrototypeOf().
  • En la práctica: Lo usas (muchas veces sin saberlo) para verificar si una propiedad pertenece al objeto y no a su herencia.

2.2. Array.prototype (La Navaja Suiza)

Es el prototipo más cargado de métodos útiles. Cuando defines const lista = [], automáticamente tienes acceso a una potencia de procesamiento enorme.

  • Qué contiene: Herramientas de transformación, búsqueda y ordenamiento.
  • Métodos clave: push(), pop(), map(), filter(), reduce(), forEach(), find(), includes().
  • En la práctica: Es el corazón de la manipulación de datos que luego renderizas en el DOM.

2.3. String.prototype (El manipulador de texto)

Aunque los strings parecen simples cadenas de texto, JS los envuelve temporalmente en este prototipo para darte superpoderes.

  • Qué contiene: Métodos de limpieza, búsqueda y partición de texto.
  • Métodos clave: split(), replace(), trim(), includes(), toUpperCase(), slice().
  • En la práctica: Vital para validar formularios o limpiar datos de un <input> antes de procesarlos.

2.4. Function.prototype (El Motor de contexto)

Sí, en JS las funciones también son objetos y tienen su propio prototipo. Esto es lo que permite que las funciones tengan métodos.

  • Qué contiene: Herramientas para controlar el valor de this.
  • Métodos clave: call(), apply(), bind().
  • En la práctica: Fundamental cuando trabajas con callbacks o cuando necesitas que una función se ejecute en el contexto de un objeto específico del DOM.

OTROS PROTOTIPOS NATIVOS MENOS USADOS PERO QUE DEBEMOS CONOCER:

2.5. Number.prototype

Prototipo de los números.

Métodos relevantes:

  • toFixed()
  • toString()
  • valueOf()

2.6. Date.prototype

Manejo de fechas y tiempo.

Métodos:

  • getFullYear()
  • getMonth()
  • toLocaleDateString()

2.7. RegExp.prototype

Expresiones regulares.

Métodos:

  • test()
  • exec()

✅ PROTOTIPOS NATIVOS DEL DOM (MUY IMPORTANTES)

2.8. EventTarget.prototype (La Base de la Interacción)

Es el ancestro más importante de casi todos los objetos del DOM. Si puedes hacer clic en algo, es porque hereda de aquí.

  • Responsabilidad: Permitir que los objetos reciban y gestionen eventos.
  • Métodos clave: addEventListener(), removeEventListener(), dispatchEvent().
  • En la práctica: Es la razón por la que puedes poner un «escuchador» tanto en un botón como en el objeto window.

2.9. Node.prototype (El Arquitecto del Árbol)

Todo en el HTML es un «nodo» (una etiqueta, un texto o incluso un comentario). Este prototipo define cómo se relacionan entre sí.

  • Responsabilidad: Gestionar la estructura y la navegación entre padres e hijos.
  • Propiedades y métodos clave: appendChild(), removeChild(), parentNode, childNodes, firstChild, cloneNode().
  • En la práctica: Lo usas cada vez que insertas un elemento nuevo dentro de un div.

2.10. Element.prototype (El Gestor de Etiquetas)

Este prototipo se enfoca específicamente en los nodos que son etiquetas HTML (ignorando nodos de texto o comentarios).

  • Responsabilidad: Manipular atributos, clases y realizar búsquedas internas.
  • Propiedades y métodos clave: querySelector(), querySelectorAll(), getAttribute(), setAttribute(), classList, innerHTML, id.
  • En la práctica: Es el «caballo de batalla» para cambiar el diseño o buscar elementos específicos dentro de un contenedor.

2.11. HTMLElement.prototype (El Estilista)

Es el paso previo a las etiquetas específicas. Aquí es donde los elementos ganan sus capacidades visuales y de estado.

  • Responsabilidad: Gestionar estilos, foco y accesibilidad común a cualquier etiqueta HTML.
  • Propiedades clave: style, hidden, innerText, dataset (para los atributos data-*), focus(), blur().
  • En la práctica: Cuando haces elemento.style.color = 'red', estás usando este prototipo nativo.

3. Extender los prototipos nativos.

3.1. ¿Qué significa extender los prototipos nativos?

Significa agregar nuevos métodos o propiedades a los prototipos que ya existen en JavaScript, como:

  • Array.prototype
  • String.prototype
  • Object.prototype
  • Element.prototype
  • etc.

ES DECIR: Modificar el comportamiento de TODOS los objetos de ese tipo.

3.2. ¿Cómo extender un prototipo? (Paso a paso):

ADVERTENCIA IMPORTANTE: En entornos profesionales y librerías modernas, esto se considera una mala práctica porque puede causar colisiones con futuras actualizaciones de JavaScript o con otras librerías. Sin embargo, entender cómo hacerlo es fundamental para comprender el poder de los prototipos.

Para añadir un método, simplemente lo asignas a la propiedad .prototype del constructor nativo.

// Queremos que todos los strings tengan un método para "gritar"
if (!String.prototype.shout) { // Buena práctica: verificar si ya existe
    String.prototype.shout = function() {
        // 'this' hace referencia al valor del string que llama al método
        return this.toUpperCase() + "!!!";
    };
}

const frase = "hola mundo";
console.log(frase.shout()); // "HOLA MUNDO!!!"Lenguaje del código: JavaScript (javascript)

Explicación del código:

  • String.prototype: Accedemos al almacén de métodos de todos los strings.
  • this: Es la clave. Dentro de un método de prototipo, this apunta a la instancia que lo está ejecutando.
  • Importante: No uses arrow functions aquí, porque las funciones flecha no tienen su propio this y no funcionará.

3.2. Ejemplo práctico para el DOM

Imagina que quieres que todos los elementos que selecciones tengan un método simple para ocultarlos sin escribir .style.display = 'none' cada vez.

// Extendemos el prototipo de los elementos HTML
HTMLElement.prototype.fadeOut = function() {
    this.style.transition = "opacity 0.5s";
    this.style.opacity = "0";
    setTimeout(() => {
        this.style.display = "none";
    }, 500);
};

// Uso en el proyecto:
const boton = document.querySelector("#btn-enviar");
boton.fadeOut(); // El botón desaparecerá con una transiciónLenguaje del código: JavaScript (javascript)

4.¿Cómo puedo inspeccionar y visualizar la cadena de prototipos?

Aquí tienes las tres formas principales de hacerlo, desde lo visual hasta lo programático.

4.1. El método visual: console.dir()

A diferencia de console.log() (que te muestra el valor del objeto), console.dir() te muestra la estructura jerárquica completa del objeto, permitiéndote navegar por sus propiedades ocultas.

Cómo hacerlo:

  1. Abre tu consola (F12).
  2. Escribe el siguiente código:
const miBotón = document.createElement('button');
console.dir(miBotón);Lenguaje del código: JavaScript (javascript)

Qué buscar: Al desplegar el objeto en la consola, busca una propiedad al final llamada [[Prototype]]. Al abrirla, verás el prototipo del cual hereda. Si sigues abriendo los [[Prototype]] que aparecen dentro de cada nivel, estarás «escalando» manualmente la cadena de prototipos hasta llegar a Object.

4.2. El método programático: Object.getPrototypeOf()

Si necesitas inspeccionar la cadena mediante código (por ejemplo, para depurar), esta es la forma estándar y moderna.

const lista = [1, 2, 3];

// Obtenemos el prototipo inmediato
const proto1 = Object.getPrototypeOf(lista);
console.log(proto1 === Array.prototype); // true (es un Array)

// Subimos un nivel más
const proto2 = Object.getPrototypeOf(proto1);
console.log(proto2 === Object.prototype); // true (es un Objeto)

// El final de la cadena
const proto3 = Object.getPrototypeOf(proto2);
console.log(proto3); // nullLenguaje del código: JavaScript (javascript)

4.3. El método «Profe»: Función para mapear la cadena completa

He preparado esta función para que puedas visualizar la jerarquía de cualquier elemento del DOM de un solo golpe en la consola. Es ideal para estudiar cómo se conectan los prototipos nativos que vimos antes.

function visualizarCadena(obj) {
    let cadena = [];
    let actual = obj;

    // Recorremos mientras el prototipo no sea null
    while (actual !== null) {
        // Obtenemos el nombre del constructor del prototipo actual
        const nombre = actual.constructor.name || "Sin Nombre";
        cadena.push(nombre);
        // Subimos al siguiente eslabón
        actual = Object.getPrototypeOf(actual);
    }

    console.log("Jerarquía encontrada:");
    console.log(cadena.join(" -> "));
}

// Ejemplo con un input de HTML
const input = document.createElement('input');
visualizarCadena(input);
// Salida esperada: HTMLInputElement -> HTMLElement -> Element -> Node -> EventTarget -> ObjectLenguaje del código: JavaScript (javascript)

Explicación de los conceptos clave:

  • [[Prototype]]: Es el nombre que usa el navegador en su interfaz para mostrar la propiedad interna que conecta los objetos.
  • .constructor.name: Nos ayuda a identificar qué «plano maestro» generó ese prototipo (por ejemplo, si fue Array, HTMLElement, etc.).
  • null: Es el indicador de que hemos llegado al origen del universo en JavaScript.

¿Por qué esto es útil en la práctica?

Si alguna vez intentas usar un método como .forEach() en algo que te devuelve el DOM (como un HTMLCollection) y te da un error de «is not a function», puedes usar visualizarCadena() para confirmar que ese objeto no tiene a Array en su cadena de prototipos, y por lo tanto, no hereda sus métodos.

Deja un comentario

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