Evitar múltiples copias de los métodos de objetos en JavaScript

Una de las primeras cosas que tenemos que hacer es evitar múltiples copias de los métodos de objetos. Para documentar este tema expondré un ejemplo donde se evidencia la duplicidad de métodos y cómo podemos mejorarlo. En este primer ejemplo declaramos el objeto objeto1 del cual haremos dos instancias ins1 e ins2. Usaremos el método clásico con la palabra reservada this.

Ejemplo: Objeto 1

propiedad de la instancia 1
propiedad de la instancia 2
si los dos métodos ver() de las dos instancias son el mismo método.
función ver() de la instancia 2
Mensajes:
 

El código es el siguiente. El objeto tiene la propiedad prop y el método ver(), que simplemente extrae el valor de esa propiedad y lo vuelca en un elemento de la página:

constructor objetos javascript Cada uno de los botones ver ejecuta el método ver() de su instancia, extrayendo el valor de su única propiedad. Con Developer Tools de Chrome podemos ver las dos instancias creadas ins1, ins2. Hasta ahora puede que parezca que no vemos nada extraño. Cada instancia tiene su propiedad y su método. Pero ¿para qué necesitamos el mismo método declarado en cada instancia?. Si el método hace lo mismo en todas las instancias esto es un desaprovechamiento de recursos, pues para el navegador son métodos distintos con el consiguiente desaprovechamiento de memoria para cada uno. ¿Y son realmente distintos?. Con el botón comprobar si son distintos hacemos ins1.ver === ins2.ver resultando que estos dos métodos son diferentes. El código de las dos funciones tiene el mismo contenido, pero no son la misma función. Además si pulsamos el botón para cambiar función ver() de la instancia 2 y luego pulsamos los botones ver de cada instancia, observaremos que hemos cambiado la funcionalidad del método ver() de la segunda instancia. Esto es porque las funciones declaradas son también variables. Así ins2.ver es una variable de tipo Function que, como cualquier otra variable, podemos modificar. Y efectivamente, la variable ins2.ver sigue siendo distinta de la variable ins1.ver.

Creando objetos con prototype en JavaScript

Tener múltiples copias de los mismos métodos supone un desaprovechamiento de recursos. Una forma de evitarlo es usando prototype. El asunto es declarar los métodos en el prototipo del objeto, no en las instancias. Veámos este segundo ejemplo.

Ejemplo: Objeto 2

propiedad de la instancia 3
propiedad de la instancia 4
si los dos métodos ver() de las dos instancias son el mismo método.
prototipo ver() del objeto
función ver() de la instancia 4
función ver() de la instancia 4
Mensajes:
 

Hemos creado dos instancias del nuevo objeto objeto2. En éste sólo declaramos las propiedades, no los métodos. El método ver() lo incorporamos con objeto2.prototype.ver = function() {...}.

prototype JavaScript Puede probar los botones ver de ambas instancias que nos devolverán los valores de su propiedad ins3.prop e ins4.prop. Con el botón comprobar vemos que ins3.ver() es igual que ins4.ver, se trata de la misma función. En la captura de pantalla del Developer Tools se presenta ver() dentro de __proto__, es decir, el prototype que es objeto2.

Con el botón cambiar prototipo ver() del objeto modificamos la funcionalidad del método compartido para que presente un mensaje diferente para todas las instancias, como puede comprobar pulsando luego los dos botones ver. Podemos volver a comprobar que ins3.ver === ins4.ver siendo la misma función.

Si pulsamos el botón cambiar función ver() de la instancia 4 sucederá que esa instancia agregará (mejor dicho, sobrescribirá) el método ins4.ver() del prototipo como una función diferente. Puede verlo pulsando ahora el botón de comprobar dando que no son iguales ins3.ver e ins4.ver. Ambas tienen distinto código. Puede quitar esa función sobreescrita con el botón eliminar y la situación vuelve al punto de partida, el método ins4.ver() es ahora de nuevo el del prototipo.

Aún podemos hacer algunas pruebas más. Recordemos que en el primer apartado se construye a partir de objeto1 la instancia ins1, donde prop y ver son su propiedad y método respectivamente. Con hasOwnProperty(propiedad) podemos preguntar si esa instancia posee una determinada propiedad o método simplemente haciendo alert(ins1.hasOwnProperty('prop')) o alert(ins1.hasOwnProperty('ver')) en los siguientes botones:

Ejemplo:


Vemos que ins1 posee prop y ver. Hagamos lo mismo con la instancia ins3 construida a partir de objeto2 en el ejemplo de este apartado:

Ejemplo:


Vemos que ins3 no posee ver(). Y entonces ¿de quién es?:

Ejemplo:

El prototipo de objeto2 es el poseedor de ver. Lo importante aquí es que prototype pertenece a objeto2, no a la instancia ins3, tal como también refleja la captura de pantalla del Developer Tools en la imagen anterior. Y sólo hay un único objeto2 por lo que también sólo habrá un único método ver.


En resumen, usar el prototipo para declarar un método de un objeto tiene las siguientes ventajas:

  • Compartimos el mismo método con todas las instancias, no habiendo declaraciones duplicadas con el mismo contenido en cada instancia con la consiguiente merma de recursos.
  • Podemos modificar un método con el prototipo y se modifica en todas las instancias creadas y en las nuevas que se puedan crear a continuación.
  • Aún podemos sobrescribir un método particular de una instancia sin que afecte a la funcionalidad de ese método en las otras instancias.
  • También podemos usar el prototipo para agregar propiedades compartidas por todas las instancias, pues al fin y al cabo desde el punto de vista del prototipo no hay diferencia entre un método compartido y una propiedad compartida.