El Prototipo (Object.prototype): Fundamento de la Herencia
Entiende cómo Object.prototype funciona como el fundamento de la herencia en JavaScript y cómo todos los objetos heredan propiedades y métodos.
TL;DR - Resumen rápido
- Object.prototype es el prototipo de todos los objetos en JavaScript
- __proto__ apunta al prototipo, prototype es propiedad de funciones
- Los objetos heredan propiedades y métodos de su prototipo
- La cadena de prototipos permite buscar propiedades en ancestros
- Object tiene métodos estáticos, Object.prototype tiene métodos de instancia
- Modificar Object.prototype afecta a todos los objetos
Introducción al Prototipo
Object.prototype es el objeto prototipo fundamental en JavaScript. Es el objeto del cual heredan todos los demás objetos. Cuando creas un objeto usando new Object() o literales de objeto, ese objeto hereda automáticamente propiedades y métodos de Object.prototype.
Este mecanismo de herencia basado en prototipos es lo que hace que JavaScript sea un lenguaje orientado a objetos. A diferencia de lenguajes como Java o C++ que usan herencia de clases, JavaScript usa una cadena de prototipos para compartir comportamiento entre objetos.
Por qué es importante
Entender Object.prototype es fundamental para dominar JavaScript. Es la base de cómo funcionan los objetos, los arrays, las funciones y casi todo en el lenguaje.
¿Qué es Object.prototype?
Object.prototype es un objeto nativo que contiene propiedades y métodos que son compartidos por todos los objetos en JavaScript. Es como un "molde" o "plantilla" de la cual se crean todos los demás objetos.
En este ejemplo, creamos un objeto vacío y luego agregamos un método a Object.prototype. Como resultado, cualquier objeto creado posteriormente tendrá acceso a ese método, demostrando que todos los objetos comparten el mismo prototipo.
Compartición automática
Esta característica es muy eficiente en términos de memoria. En lugar de que cada objeto tenga su propia copia de un método, todos comparten la misma referencia al método en Object.prototype.
__proto__ vs prototype
Una de las confusiones más comunes en JavaScript es la diferencia entre __proto__ y prototype. Ambos están relacionados con prototipos, pero tienen propósitos completamente diferentes y existen en contextos distintos.
En este ejemplo vemos que prototype es una propiedad de funciones constructoras, mientras que __proto__ es una propiedad de instancias que apunta al prototype de su constructor. Todos los objetos creados con new Persona comparten el mismo __proto__, que es Persona.prototype.
__proto__ está deprecated
Aunque __proto__ funciona, está deprecated. En código moderno, usa Object.getPrototypeOf() para obtener el prototipo y Object.setPrototypeOf() para establecerlo.
Object.getPrototypeOf() y Object.setPrototypeOf()
La forma moderna y recomendada de trabajar con prototipos es usando Object.getPrototypeOf() para obtener el prototipo de un objeto y Object.setPrototypeOf() para cambiarlo. Estos métodos son más explícitos y están estandarizados.
Object.getPrototypeOf(obj) retorna el prototipo del objeto, mientras que Object.setPrototypeOf(obj, proto) establece un nuevo prototipo. Sin embargo, cambiar el prototipo de un objeto existente tiene implicaciones de rendimiento y generalmente debe evitarse en código de producción.
Métodos Estáticos de Object
Object (con O mayúscula) tiene métodos estáticos que se llaman directamente en Object, no en instancias. Estos métodos son funciones auxiliares para manipular y trabajar con objetos en general.
- <strong>Object.create(proto)</strong>: Crea un nuevo objeto con un prototipo específico
- <strong>Object.keys(obj)</strong>: Devuelve un array con las propiedades enumerables del objeto
- <strong>Object.values(obj)</strong>: Devuelve un array con los valores del objeto
- <strong>Object.entries(obj)</strong>: Devuelve un array de pares [clave, valor]
- <strong>Object.getPrototypeOf(obj)</strong>: Obtiene el prototipo de un objeto
- <strong>Object.setPrototypeOf(obj, proto)</strong>: Establece el prototipo de un objeto
Este ejemplo muestra métodos estáticos de Object. Se llaman como Object.keys(objeto), no como objeto.keys(). Estos métodos operan sobre objetos pero no son heredados por las instancias.
Métodos estáticos vs de instancia
Los métodos estáticos se llaman en Object directamente (Object.keys(obj)). Los métodos de instancia se heredan de Object.prototype y se llaman en instancias (obj.hasOwnProperty()).
Métodos de Instancia
Los métodos de instancia están definidos en Object.prototype y son heredados por todos los objetos. Se llaman directamente en las instancias de objetos, no en Object.
- <strong>hasOwnProperty(prop)</strong>: Verifica si el objeto tiene una propiedad propia (no heredada)
- <strong>toString()</strong>: Convierte el objeto a string, retorna '[object Object]' por defecto
- <strong>valueOf()</strong>: Retorna el valor primitivo del objeto
- <strong>isPrototypeOf(obj)</strong>: Verifica si el objeto está en la cadena de prototipos
- <strong>propertyIsEnumerable(prop)</strong>: Verifica si una propiedad es enumerable
Estos métodos se heredan automáticamente de Object.prototype. Puedes sobrescribirlos en objetos específicos para personalizar su comportamiento, como se hace comúnmente con toString().
Object.create(null)
Puedes crear objetos sin prototipo usando Object.create(null). Estos objetos no heredan ningún método de Object.prototype, lo cual es útil para crear diccionarios o mapas puros sin propiedades heredadas que puedan causar conflictos.
Cuándo usar Object.create(null)
Usa Object.create(null) cuando necesites un objeto que funcione como un mapa puro sin propiedades heredadas. Es común en implementaciones de diccionarios y configuraciones.
Herencia a través de Prototipos
Cuando accedes a una propiedad o método de un objeto, JavaScript busca primero en el objeto mismo. Si no lo encuentra, busca en el prototipo del objeto. Si tampoco lo encuentra, continúa la búsqueda en la cadena de prototipos hasta llegar a Object.prototype.
En este ejemplo, creamos un objeto padre y un objeto hijo. El objeto hijo no tiene el método saludar(), pero cuando lo llamamos, JavaScript lo encuentra en el prototipo del padre y lo ejecuta correctamente.
Cadena de prototipos
Esta cadena de búsqueda automática es muy poderosa. Permite que los objetos hereden comportamiento sin que tengas que configurar explícitamente la herencia.
Modificar Object.prototype
Aunque no es común, puedes modificar Object.prototype para agregar o sobrescribir métodos y propiedades. Esto te permite extender o modificar el comportamiento de todos los objetos en tu aplicación.
En este ejemplo, agregamos un método personalizado a Object.prototype. Ahora todos los objetos, incluidos los que ya existen, tendrán acceso a este nuevo método.
Advertencia importante
Modificar Object.prototype afecta a todos los objetos en tu aplicación y puede causar conflictos si múltiples bibliotecas modifican el mismo método. Úsalo con precaución.
Polyfills
Antes de ES6, era común modificar Object.prototype para agregar polyfills. Por ejemplo, para agregar el método Array.prototype.includes() en navegadores antiguos, se agregaba directamente a Array.prototype.
Polyfills modernos
Hoy en día, es preferido no modificar Object.prototype directamente. En su lugar, usa Object.defineProperty() para agregar métodos a prototipos específicos cuando sea necesario.
Resumen: El Prototipo (Object.prototype)
Conceptos principales:
- •Object.prototype es el prototipo base de todos los objetos
- •__proto__ (deprecated) apunta al prototipo, prototype es de funciones
- •Usa Object.getPrototypeOf() en lugar de __proto__
- •Métodos estáticos: Object.keys(), Object.values(), Object.entries()
- •Métodos de instancia: hasOwnProperty(), toString(), valueOf()
- •La cadena de prototipos permite herencia automática
Mejores prácticas:
- •No modifiques Object.prototype en código moderno
- •Usa Object.getPrototypeOf() en lugar de __proto__
- •Usa Object.create(null) para objetos sin prototipo
- •Sobrescribe toString() para objetos personalizados
- •Usa hasOwnProperty() para verificar propiedades propias
- •Entiende la cadena de prototipos para depurar mejor