Introducción
Hace algún tiempo repasamos algunos de los patrones de diseño modulares más importantes que podemos encontrar actualmente en Javascript. Vimos el patrón del módulo tradicional, el revelado, elproxy y algunas variaciones.
Todas estas estructuras tienen como fin el agrupar una serie de bloques de código con funcionalidades compartidas permitiendo así su reutilización y portabilidad entre proyectos. Es por ejemplo el sistema con el que se articulan bibliotecas como jQuery, ZeptoJS o Mootools por ejemplo.
Gracias a estos patrones, podemos crear nuestros propios frameworks o aplicaciones cuyo código no interfiera con el de terceros. Se trata en definitiva de buenas prácticas que siempre es conveniente conocer.
Como cualquier otro patrón de diseño, la definición de estos módulos está sujeta a continua revisión y resulta frecuente encontrar variantes interesantes que mejoran su arquitectura base, su legibilidad, el rendimiento o cualquier otro parámetro ya sea mesurable o simplemente estético.
En esta ocasión, buscando nuevas reformulaciones, vamos a analizar el sistema que articula a la que posiblemente sea la biblioteca Javascript más popular en la actualidad: jQuery.
NOTA: A continuación analizaremos el código de la versión 1.6.3 de jQuery la cual es, durante la redacción de este artículo, la última disponible.
El patrón de módulo jQuery
Actualmente, jQuery utiliza la siguiente estructura del código:
Pasemos a diseccionarla paso a paso para ver cómo funciona:
El marco de trabajo principal
La estructura se enmarca en una función autoejecutable que crea un namespace propio. Ésto, permiteencapsular todo el contenido y aislarlo de cualquier otro script para evitar problemas de colisión o sobreescritura de variables:
Como ya explicamos en en su momento, aquí lo importante es que a la función autoejecutable se le pasa un solo argumento (window) mientras que recibe dos (el mismo window y undefined). El porqué de esto responde a una cuestión de rendimiento en el primer caso y a una de seguridad en el segundo:cachear el objeto window en el interior de nuestro script permite que cada vez que lo necesitemos, el intérprete no tiene que subir varios niveles hasta alcanzarlo. Con respecto a undefined, al no recibir ningún argumento, su valor se establece efectivamente como tal (sin definir) previniéndonos contra una hipotética sobreescritura anterior de esta primitiva.
Yendo un poco más lejos, en nuestro script es muy posible que en algún momento queramos interactuar con el DOM, conocer la versión del navegador para algún tipo de filtrado, o incluso extraer toda la información posible relativa a la URL del documento que ejecuta el script. Para facilitar el acceso a estos datos, jQuery los almacena en forma de variables para poder acceder rápidamente a su contenido en cualquier momento:
Con esto, cuando necesitemos utilizar alguno de los objetos anteriores, el intérprete dispondrá de ellos rápidamente sin la necesidad de ascender niveles o volver a recorrer al objeto padre.
Definiendo el core
Una vez creado el marco general y con algunas variables útiles ya declaradas, lo siguiente es crear la función principal que contendrá el núcleo o core de nuestro script. Para ello, utilizaremos una función declarada cuyo nombre se corresponderá con el de la biblioteca en la que trabajamos:
Dentro de esta función es donde se definirán los métodos públicos (la API pública) que tendremos disponibles tras su inicialización. Estos métodos deben definirse a su vez en un objeto interno que debe ser devuelto mediante el comando return al ámbito de nuestra biblioteca.Llamaremos a este objeto intermedio core:
Ese nuevo objeto core, como hemos comentado más arriba, guardará los métodos públicos de nuestra biblioteca mediante una notación simple de nombre y función a ejecutar:
Con esta estructura, conseguimos que el objeto jQuery devuelto por return, implemente la definición de los métodos que hemos declarado.
Creando los métodos de nuestra biblioteca
Para dar cierta funcionalidad a nuestra biblioteca, incluyamos dentro del core un método trim para eliminar los espacios en blanco a izquierda y derecha de una cadena dada:
En el código anterior, dentro de la variable jQuery tendremos ahora un objeto con nuestro nuevo método. Para poder utilizarlo, necesitaríamos devolver dicho objeto jQuery al ámbito global.
Salvado ese punto, solo sería cuestión de añadir más métodos al core hasta cubrir todas las necesidades o especificaciones de la aplicación.
Devolviendo la biblioteca al ámbito global
Como hemos comentado en el último ejemplo, la variable jQuery contiene el objeto con los métodos que hemos definido por lo que, si queremos asociar ese objeto al contexto global,únicamente necesitamos añadirlo al window (que siempre se corresponde con el nivel o ámbito más alto):
Ahora, el contexto global (window) cuenta con una nueva variable que en realidad contiene al objeto que hemos creado anteriormente. Como tal, posee aquellos métodos que definimos en el core y que son accesibles de forma pública mediante la notación tradicional:
Nuestra biblioteca funciona como se espera; no ha sido tan difícil! Pero como observación, rápidamente vemos que todos sus métodos son públicos. ¿Cómo podemos implementar métodos privados dentro de este esquema?
Métodos privados en el patrón jQuery
Para crear métodos que solo sean visibles (accesibles) desde el interior de nuestra biblioteca, tenemos que definirlos fuera del objeto core.
Implementemos en nuestra biblioteca anterior el sistema para comprobar tipos que tratamos en un artículo anterior: la función toType:
Si queremos que esta utilidad solo sea accesible por los métodos de nuestra biblioteca sin que pertenezca a la API pública, podemos crear un nuevo objeto private que la contenga (idea original de@acido69):
Como este nuevo objeto está fuera del jQuery, no se asocia al window y, por tanto, no llega nunca al ámbito global: permanecerá así como un método privado de nuestra biblioteca.
Para utilizar sus métodos dentro de nuestro script, bastará con llamarlo del modo tradicional ya que comparten scope:
Lo comprobamos rápidamente:
Como podemos ver, toType funciona cuando se llama desde el interior de la biblioteca pero lógicamente devuelve error si tratamos de acceder desde fuera. Hemos conseguido así restringir su visibilidad y limitar su acción exclusivamente al interior del script.
Asociando un álias
Finalmente, jQuery permite utilizar el caracter $ como un álias para invocar sus métodos:
Ambas formas son idénticas. Para asociar un álias a nuestra biblioteca, basta con añadir el nombre escogido al objeto window apuntando al valor al de la biblioteca en sí. Cambiamos únicamente la última parte de nuestro patrón:
Con este último paso, tenemos lista y funcional nuestra biblioteca utilizando una estructura similar a la que presenta jQuery.
Conclusión
En el desarrollo moderno de aplicaciones Javascript, es frecuente recurrir a los patrones de diseño para garantizar una arquitectura sólida y fiable. Tradicionalmente, hemos contado con algunos ejemplos muy interesantes como son el conocido patrón módulo, el módulo revelado o el elegante “This namespaces proxy” de James Edwards.
Profundizando en estos ejemplos, jQuery ha desarrollado un patrón propio que ha demostrado un alto rendimiento con una elegante estructura. En definitiva, se trata de una función autoejecutable que en último término asocia un nuevo objeto al contexto global del entorno de ejecución. Dicho objeto cuenta con todos los métodos públicos (el API) que queremos ofrecer al usuario (o a terceros) permitiéndonos además, restringir cómodamente la visibilidad de aquellas funcionalidades que queramos definir como privadas.
Un patrón sin duda muy interesante que bien vale un estudio.
No hay comentarios:
Publicar un comentario