El compilador closure (no confundir con el concepto de closure) es una de las múltiples dispositivos disponibles para mantener vuestro código Javascript un es
caso más saludable. Es la alternativa que mejor conozco, y por eso voy a relatar cómo funciona. Closure es un compilador capaz de convertir lenguaje Javascript desarrollado con anotaciones (en los comentarios), a otro Javascript optimizado para su ejecución y habitualmente más pequeño. Además, realiza un análisis estático de vuestro código para descubrir yerros
comunes y
comprobar las anotaciones. En mi opinión, este análisis estático es la funcionalidad más interesante de este compilador, ya que tienen lugar múltiples minificadores de código que resuelven la otra parte. Un
ejemplo de estas anotaciones: /** * @param {number x Un argumento cualquiera. * @constructor * @extends {MiOtraClase */ function MiClase(x) { this.x = x; /** * @override */ MiClase.prototype.mostrar = function() { window.console.log(this.x); TiposEste compilador permite,
entre otras muchas cosas, declarar
tipos estáticos y verifica que el código satisface los contratos introducidos por dichos tipos. Una mayor ventaja de este compilador es que los tipos se introducen mediante comentarios, con una sintaxis muy similar a Javadoc o Doxygen,
como se puede apreciar en el
ejemplo anterior. Esto tiene dos consecuencias muy interesantes: El tipado no es intrusivo, el código Seguid siendo Javascript, y se puede valorar en cualquier intérprete de este lenguaje (por ejemplo, cualquier navegador). Impulsa la documentación del código. Ya que poseo que añadir @param {tipo nombre para que el compilador haga el esfuerzo sucio y valide los tipos, no cuesta nada escribir un escaso más y aclarar para qué sirve el parámetro. Este es un ejemplo del tipo de dificultades que resuelve este compilador: function suma(a, b) { return a + b; var fruto = suma("10", 2); window.console.log(resultado); Este código imprime por
pantalla ?102″, en espacio de ?12″. Dado que se emplean persistentes en el ejemplo, es muy sencillo ver el yerro y solucionarlo, pero si el primer argumento fue en verdad el valor tomado de un tema de texto HTML, entonces ya no sería tan evidente, aunque el asunto sería el mismo. Este es el mismo ejemplo tipado por closure: /** * @param {number a Primer operando. * @param {number b Segundo operando. * @return {number El resultado. */ function suma(a, b) { return a + b; var fruto = suma("10", 2); window.console.log(resultado); Si ahora se ejecuta el compilador, se obtiene lo siguiente: $
java -jar compiler.jar --warning_level VERBOSE \ test.js > /dev/null /tmp/test.js:9: WARNING - actual parameter 1 of suma does not match formal parameter found : string required: number var fruto = suma("10", 2); ^ En el ejemplo anterior, se está redirigiendo la salida del compilador (el código minimizado y optimizado) a /dev/null. En ámbitos de producción esa salida puede ser muy interesante por las mejoras de velocidad de carga y ejecución que implica, pero la idea que quiero transmitir aquí es que inclusive si no interesa ese código ?minificado?, el compilador aporta mucho valor al considerar el código y descubrir errores. Estas anotaciones no se quedan simplemente en parámetros y variables, facultan declarar interfaces, proteger sobrecargas con @override idéntico se haría en Java, anotar herencia, declarar constructores, visibilidad, e inclusive nombrar tipos complejos por comodidad. Aquí hay una referencia bastante actualizada de las posibilidades. En versiones recientes del compilador hay determinadas
funciones experimentales
como tipos genéricos (similar a los generics de Java o los templates de C++), que dotan de más expresividad al sistema de tipado y todavía no están documentadas en felicidad referencia, aunque determinadas bibliotecas ya los usan Optimizaciones Ya que se trata de un compilador, y no un simple parser capaz de reducir lugares en blanco y renombrar variables, es capaz de
realizar determinadas cosas típicas de compiladores,
como inlining y precálculo de expresiones. Un ejemplo: /** * @param {number x * @param {number y * @return {number */ function suma(x, y) { return x + y; window.console.log(suma(3, 2)); Es bastante evidente que este código va a presentar en la consola del navegador el número 5, y sin embargo la mayoría de minificadores generarán un código compacto que aún declarará la función y la llamará. Closure es capaz de ir un escaso más allá: $
java -jar compiler.jar --warning_level VERBOSE \ --compilation_level ADVANCED_OPTIMIZATIONS \ test2.js > /dev/null window.console.log(5); En este caso el compilador descubrió que permitía precalcular el fruto de llamar a la función suma e inyectarlo en espacio de la llamada a la función, fruto en un código más compacto y veloz de ejecutar. En muchos casos es indispensable tener información de tipos para realizar optimizaciones
como esa. Todavía no alcanza, sin embargo, los niveles de GCC, capaz de precalcular inclusive el fruto de funciones recursivas (por desgracia GCC todavía no soporta Javascript). No intrusivoTanto si uno está interesado en las optimizaciones que closure puede realizar
como si no, este compilador es una dispositivo muy interesante porque no genera una dependencia tecnológica en un programa. Se puede descartar y todo el código del programa seguirá funcionando igual. Además, puede convivir perfectamente con otras dispositivos de análisis estático de código Javascript que encuentren otros yerros y vulnerabilidades, o con otros minificadores. Es cierto que obliga a describir un escaso mejor los contratos del código, señalando tipos, herencias, etc. de una manera homogénea, y esto, en mi opinión, mejora mucho la
legibilidad del código, y es un esfuerzo que se debería realizar en cualquier caso si se pretende que el código sea mantenible.