Escribir JavaScript modular con AMD, CommonJS y ES Harmony

Tweet

Modularidad La importancia de desacoplar tu aplicación

Cuando decimos que una aplicación es modular, generalmente nos referimos a que está compuesta por un conjunto de piezas de funcionalidad altamente desacopladas y distintas, almacenadas en módulos. Como probablemente sepas, el acoplamiento débil facilita el mantenimiento de las aplicaciones al eliminar las dependencias cuando es posible. Cuando esto se implementa de manera eficiente, es bastante fácil ver cómo los cambios en una parte de un sistema pueden afectar a otra.

Sin embargo, a diferencia de algunos lenguajes de programación más tradicionales, la iteración actual de JavaScript (ECMA-262) no proporciona a los desarrolladores los medios para importar tales módulos de código de una manera limpia y organizada. Es una de las preocupaciones con las especificaciones que no han requerido una gran reflexión hasta los últimos años, cuando la necesidad de aplicaciones de JavaScript más organizadas se hizo evidente.

En cambio, los desarrolladores en la actualidad se ven obligados a recurrir a las variaciones de los patrones de módulo u objeto literal. Con muchos de ellos, las secuencias de comandos de los módulos se encadenan en el DOM con espacios de nombres que se describen mediante un único objeto global donde todavía es posible incurrir en colisiones de nombres en su arquitectura. Tampoco hay una forma limpia de manejar la gestión de dependencias sin algún esfuerzo manual o herramientas de terceros.

Mientras que las soluciones nativas a estos problemas llegarán en ES Harmony, la buena noticia es que escribir JavaScript modular nunca ha sido más fácil y puedes empezar a hacerlo hoy.

En este artículo, vamos a ver tres formatos para escribir JavaScript modular: AMD, CommonJS y las propuestas para la próxima versión de JavaScript, Harmony.

Preludio Una nota sobre los cargadores de scripts

Es difícil hablar de los módulos AMD y CommonJS sin hablar del elefante de la habitación: los cargadores de scripts. En la actualidad, la carga de scripts es un medio para conseguir un objetivo, ese objetivo es un JavaScript modular que pueda ser utilizado en las aplicaciones actuales – para esto, el uso de un cargador de scripts compatible es desafortunadamente necesario. Para sacar el máximo provecho de este artículo, recomiendo obtener una comprensión básica de cómo funcionan las herramientas populares de carga de scripts para que las explicaciones de los formatos de los módulos tengan sentido en su contexto.

Hay una serie de grandes cargadores para manejar la carga de módulos en los formatos AMD y CJS, pero mis preferencias personales son RequireJS y curl.js. Los tutoriales completos sobre estas herramientas están fuera del alcance de este artículo, pero puedo recomendar la lectura del post de John Hann sobre curl.js y la documentación de la API de RequireJS de James Burke para obtener más información.

Desde una perspectiva de producción, se recomienda el uso de herramientas de optimización (como el optimizador de RequireJS) para concatenar scripts para el despliegue cuando se trabaja con tales módulos. Curiosamente, con el shim de Almond AMD, RequireJS no necesita ser rodado en el sitio desplegado y lo que podría considerar un cargador de scripts puede ser fácilmente desplazado fuera del desarrollo.

Dicho esto, James Burke probablemente diría que ser capaz de cargar dinámicamente los scripts después de la carga de la página todavía tiene sus casos de uso y RequireJS puede ayudar con esto también. Con estas notas en mente, empecemos.

AMD Un formato para escribir JavaScript modular en el navegador

El objetivo general del formato AMD (Asynchronous Module Definition) es proporcionar una solución para el JavaScript modular que los desarrolladores pueden utilizar hoy en día. Nació de la experiencia del mundo real de Dojo usando XHR+eval y los proponentes de este formato querían evitar que cualquier solución futura sufriera de las debilidades de las del pasado.

El formato de módulo AMD en sí mismo es una propuesta para definir módulos donde tanto el módulo como las dependencias pueden ser cargados asíncronamente. Tiene una serie de ventajas distintas, incluyendo el hecho de ser asíncrono y altamente flexible por naturaleza, lo que elimina el estrecho acoplamiento que uno podría encontrar comúnmente entre el código y la identidad del módulo. Muchos desarrolladores disfrutan usándolo y uno podría considerarlo un paso fiable hacia el sistema de módulos propuesto para ES Harmony.

AMD comenzó como un borrador de especificación para un formato de módulo en la lista de CommonJS, pero como no fue capaz de alcanzar un consenso total, el desarrollo posterior del formato se trasladó al grupo amdjs.

Hoy en día es adoptado por proyectos como Dojo (1.7), MooTools (2.0), Firebug (1.8) e incluso jQuery (1.7). Aunque el término CommonJS AMD ha sido visto en la naturaleza en ocasiones, es mejor referirse a él como sólo AMD o soporte de módulos asíncronos, ya que no todos los participantes en la lista CJS deseaban perseguirlo.

Nota: Hubo un tiempo en el que la propuesta fue referida como Modules Transport/C, sin embargo, como la especificación no estaba orientada a transportar módulos CJS existentes, sino más bien, para definir módulos, tenía más sentido optar por la convención de nomenclatura AMD.

Cómo empezar con los módulos

Los dos conceptos clave que hay que tener en cuenta aquí son la idea de un método define para facilitar la definición de módulos y un método require para manejar la carga de dependencias. define se utiliza para definir módulos con nombre o sin nombre basados en la propuesta utilizando la siguiente firma:

Como puedes ver por los comentarios en línea, el module_id es un argumento opcional que normalmente sólo se requiere cuando se utilizan herramientas de concatenación que no son de AMD (puede haber algunos otros casos extremos en los que también es útil). Cuando este argumento se omite, llamamos al módulo anónimo.

Cuando se trabaja con módulos anónimos, la idea de la identidad de un módulo es DRY, lo que hace que sea trivial evitar la duplicación de nombres de archivo y código. Debido a que el código es más portable, puede ser fácilmente movido a otros lugares (o alrededor del sistema de archivos) sin necesidad de alterar el propio código o cambiar su ID. El module_id es equivalente a las rutas de las carpetas en los paquetes simples y cuando no se utiliza en los paquetes. Los desarrolladores también pueden ejecutar el mismo código en varios entornos simplemente utilizando un optimizador AMD que funcione con un entorno CommonJS como r.js.

Volviendo a la firma de definición, el argumento dependencies representa un array de dependencias que son requeridas por el módulo que estás definiendo y el tercer argumento (‘definition function’) es una función que se ejecuta para instanciar tu módulo. Un módulo básico podría definirse de la siguiente manera:

Entendiendo a AMD: define()

require por otro lado se usa típicamente para cargar código en un archivo JavaScript de nivel superior o dentro de un módulo si se desea obtener dependencias dinámicamente. ¡Un ejemplo de su uso es:

Entendiendo AMD: require()

Dependencias cargadas dinámicamente

Entendiendo AMD: plugins

El siguiente es un ejemplo de definición de un plugin compatible con AMD:

Nota: Aunque css! se incluye para cargar las dependencias de CSS en el ejemplo anterior, es importante recordar que este enfoque tiene algunas advertencias, como que no es posible establecer completamente cuándo se carga el CSS. Dependiendo de cómo enfoques tu construcción, también puede resultar en que el CSS se incluya como una dependencia en el archivo optimizado, así que usa el CSS como una dependencia cargada en tales casos con precaución.

Carga de módulos AMD usando require.js

Loading AMD Modules Using curl.js

Modules With Deferred Dependencies

Why Is AMD A Better Choice For Writing Modular JavaScript?

  • Provides a clear proposal for how to approach defining flexible modules.
  • Significativamente más limpio que el actual espacio de nombres global y las soluciones de etiquetas <script> en las que muchos de nosotros confiamos. Hay una forma limpia de declarar los módulos independientes y las dependencias que puedan tener.
  • Las definiciones de los módulos están encapsuladas, ayudándonos a evitar la contaminación del espacio de nombres global.
  • Funciona mejor que algunas soluciones alternativas (por ejemplo, CommonJS, que veremos en breve). No tiene problemas con el cross-domain, local o de depuración y no tiene una dependencia de las herramientas del lado del servidor para ser utilizado. La mayoría de los cargadores de AMD soportan la carga de módulos en el navegador sin un proceso de construcción.
  • Proporciona un enfoque de «transporte» para incluir múltiples módulos en un solo archivo. Otros enfoques como CommonJS todavía tienen que acordar un formato de transporte.
  • Es posible cargar perezosamente los scripts si esto es necesario.

Módulos AMD con Dojo

Definir módulos compatibles con AMD usando Dojo es bastante sencillo. Como en el caso anterior, defina cualquier dependencia del módulo en un array como primer argumento y proporcione una devolución de llamada (factory) que ejecutará el módulo una vez que se hayan cargado las dependencias. e.g:

define(, function( Tooltip ){ //Our dijit tooltip is now available for local use new Tooltip(...);});

Note la naturaleza anónima del módulo que ahora puede ser consumido por un cargador asíncrono de Dojo, RequireJS o el cargador de módulos estándar dojo.require() que puede estar acostumbrado a usar.

Para aquellos que se preguntan sobre la referenciación de módulos, hay algunas gotas interesantes que son útiles para saber aquí. Aunque la forma defendida por AMD de referenciar módulos los declara en la lista de dependencias con un conjunto de argumentos coincidentes, esto no está soportado por el sistema de construcción de Dojo 1.6 – realmente sólo funciona para cargadores compatibles con AMD. e.g:

define(, function( cookie, Tooltip ){ var cookieValue = cookie("cookieName"); new Tree(...); });

Esto tiene muchos avances sobre el namespacing anidado, ya que los módulos ya no necesitan referenciar directamente espacios de nombres completos cada vez – todo lo que requerimos es la ruta ‘dojo/cookie’ en las dependencias, que una vez aliasada a un argumento, puede ser referenciada por esa variable. Esto elimina la necesidad de escribir repetidamente ‘dojo.’ en tus aplicaciones.

Nota: Aunque Dojo 1.6 no soporta oficialmente los módulos AMD basados en el usuario (ni la carga asíncrona), es posible conseguir que esto funcione con Dojo usando un número de cargadores de scripts diferentes. En la actualidad, todos los módulos del núcleo de Dojo y Dijit han sido transformados a la sintaxis AMD y la mejora del soporte general de AMD probablemente aterrizará entre 1.7 y 2.0.

El último inconveniente a tener en cuenta es que si desea continuar utilizando el sistema de construcción de Dojo o desea migrar los módulos más antiguos a este nuevo estilo AMD, la siguiente versión más verbosa permite una migración más fácil. Fíjate que dojo y dijit también se referencian como dependencias:

Patrones de diseño de módulos AMD (Dojo)

Si has seguido alguno de mis posts anteriores sobre las ventajas de los patrones de diseño, sabrás que pueden ser muy eficaces para mejorar la forma en que abordamos la estructuración de soluciones a problemas comunes de desarrollo. John Hann dio recientemente una excelente presentación sobre los patrones de diseño de los módulos de AMD, cubriendo Singleton, Decorator, Mediator y otros. Recomiendo encarecidamente revisar sus diapositivas si tienes la oportunidad.

Algunos ejemplos de estos patrones se pueden encontrar a continuación:

Patrón Decorator:

Patrón adaptador

Módulos AMD con jQuery

Los fundamentos

A diferencia de Dojo, jQuery realmente sólo viene con un archivo, sin embargo dada la naturaleza basada en plugins de la librería, podemos demostrar lo sencillo que es definir un módulo AMD que lo utilice a continuación.

Sin embargo, hay algo que falta en este ejemplo y es el concepto de registro.

Registrar jQuery como un módulo compatible con asíncrono

Una de las características clave que aterrizó en jQuery 1.7 fue el soporte para registrar jQuery como un módulo asíncrono. Hay un número de cargadores de scripts compatibles (incluyendo RequireJS y curl) que son capaces de cargar módulos usando un formato de módulo asíncrono y esto significa que se requieren menos hacks para que las cosas funcionen.

Como resultado de la popularidad de jQuery, los cargadores de AMD necesitan tener en cuenta múltiples versiones de la biblioteca que se cargan en la misma página ya que idealmente no quieres varias versiones diferentes cargando al mismo tiempo. Los cargadores tienen la opción de tener en cuenta específicamente este problema o de indicar a sus usuarios que existen problemas conocidos con los scripts de terceros y sus bibliotecas.

Lo que aporta la adición 1.7 es que ayuda a evitar problemas con otro código de terceros en una página que cargue accidentalmente una versión de jQuery en la página que el propietario no esperaba. Usted no quiere que otras instancias clobbering su propia y por lo que este puede ser de beneficio.

La forma en que esto funciona es que el cargador de secuencias de comandos que se emplea indica que soporta múltiples versiones de jQuery especificando que una propiedad, define.amd.jQuery es igual a true. Para aquellos interesados en detalles de implementación más específicos, registramos jQuery como un módulo con nombre, ya que existe el riesgo de que pueda ser concatenado con otros archivos que pueden utilizar el método define() de AMD, pero no utilizar un script de concatenación adecuado que entienda las definiciones de módulos anónimos de AMD.

El AMD con nombre proporciona una manta de seguridad de ser a la vez robusto y seguro para la mayoría de los casos de uso.

Smarter jQuery Plugins

Recientemente he discutido algunas ideas y ejemplos de cómo los plugins de jQuery podrían ser escritos utilizando patrones de definición de módulo universal (UMD) aquí. Los UMDs definen módulos que pueden funcionar tanto en el cliente como en el servidor, así como con todos los cargadores de scripts populares disponibles en este momento. Mientras que esto es todavía un área nueva con un montón de conceptos que aún se están finalizando, siéntase libre de mirar los ejemplos de código en el título de la sección AMD && CommonJS a continuación y hágame saber si usted siente que hay algo que podríamos hacer mejor.

¿Qué cargadores de scripts & soportan AMD?

En el navegador:
Del lado del servidor:
  • RequireJS http://requirejs.org
  • PINF http://github.com/pinf/loader-js

Conclusiones de AMD

Los anteriores son ejemplos muy triviales de lo realmente útiles que pueden ser los módulos de AMD, pero espero que sirvan de base para entender su funcionamiento.

Tal vez le interese saber que muchas grandes aplicaciones y empresas visibles utilizan actualmente módulos AMD como parte de su arquitectura. Entre ellas se encuentran IBM y el iPlayer de la BBC, lo que pone de manifiesto la seriedad con la que este formato está siendo considerado por los desarrolladores a nivel empresarial.

Para conocer más razones por las que muchos desarrolladores están optando por utilizar módulos AMD en sus aplicaciones, te puede interesar este post de James Burke.

CommonJS Un formato de módulo optimizado para el servidor

CommonJS es un grupo de trabajo voluntario cuyo objetivo es diseñar, prototipar y estandarizar las API de JavaScript. Hasta la fecha han intentado ratificar estándares tanto para módulos como para paquetes. La propuesta de módulos de CommonJS especifica una API simple para declarar módulos del lado del servidor y, a diferencia de AMD, intenta cubrir un conjunto más amplio de preocupaciones como io, sistema de archivos, promesas y más.

Comenzando

Desde el punto de vista de la estructura, un módulo CJS es una pieza reutilizable de JavaScript que exporta objetos específicos que se ponen a disposición de cualquier código dependiente – normalmente no hay envolturas de funciones alrededor de tales módulos (por lo que no verás define utilizado aquí, por ejemplo).

En un alto nivel contienen básicamente dos partes principales: una variable libre llamada exports que contiene los objetos que un módulo desea poner a disposición de otros módulos y una función require que los módulos pueden utilizar para importar las exportaciones de otros módulos.

Entendiendo CJS: require() y exports

Consumo básico de exports

AMD-equivalente del primer ejemplo de CJS

Consumiendo múltiples dependencias

app.js
bar.js
exports.name = 'bar';
foo.js
require('./bar');exports.helloWorld = function(){ return 'Hello World!!''}

¿Qué Frameworks de carga & soportan CJS?

En el navegador:
  • curl.js http://github.com/unscriptable/curl
  • SproutCore 1.1 http://sproutcore.com
  • PINF http://github.com/pinf/loader-js
  • (y más)
Del lado del servidor:

¿Es CJS adecuado para el navegador?

Hay desarrolladores que creen que CommonJS es más adecuado para el desarrollo del lado del servidor, lo que es una de las razones por las que actualmente hay un nivel de desacuerdo sobre qué formato debe y será utilizado como el estándar de facto en la era pre-Harmony en adelante. Algunos de los argumentos en contra de CJS incluyen la observación de que muchas APIs de CommonJS abordan características orientadas al servidor que uno simplemente no sería capaz de implementar a nivel de navegador en JavaScript – por ejemplo, io, system y js podrían considerarse no implementables por la naturaleza de su funcionalidad.

Dicho esto, es útil saber cómo estructurar los módulos CJS a pesar de todo para que podamos apreciar mejor cómo encajan al definir los módulos que pueden ser utilizados en todas partes. Entre los módulos que tienen aplicaciones tanto en el cliente como en el servidor se encuentran los motores de validación, de conversión y de plantillas. La forma en que algunos desarrolladores están enfocando la elección del formato a utilizar es optando por CJS cuando un módulo puede ser utilizado en un entorno del lado del servidor y utilizando AMD si este no es el caso.

Como los módulos AMD son capaces de usar plugins y pueden definir cosas más granulares como constructores y funciones esto tiene sentido. Los módulos CJS sólo son capaces de definir objetos que pueden ser tediosos de trabajar si estás tratando de obtener constructores de ellos.

Aunque está más allá del alcance de este artículo, también puede haber notado que había diferentes tipos de métodos ‘require’ mencionados al discutir AMD y CJS.

La preocupación con una convención de nomenclatura similar es, por supuesto, la confusión y la comunidad está actualmente dividida en cuanto a los méritos de una función require global. La sugerencia de John Hann aquí es que en lugar de llamarlo ‘require’, que probablemente no lograría el objetivo de informar a los usuarios sobre la diferencia entre un require global y uno interno, puede tener más sentido renombrar el método de carga global de otra manera (por ejemplo, el nombre de la biblioteca). Es por esta razón que un cargador como curl.js utiliza curl() en lugar de require.

AMD && CommonJS Estándares competitivos, pero igualmente válidos

Aunque este artículo ha puesto más énfasis en el uso de AMD sobre CJS, la realidad es que ambos formatos son válidos y tienen un uso.

AMD adopta un enfoque de desarrollo basado en el navegador, optando por un comportamiento asíncrono y una compatibilidad hacia atrás simplificada, pero no tiene ningún concepto de E/S de archivos. Soporta objetos, funciones, constructores, cadenas, JSON y muchos otros tipos de módulos, ejecutándose de forma nativa en el navegador. Es increíblemente flexible.

CommonJS, por otro lado, adopta un enfoque «server-first» (primero el servidor), asumiendo un comportamiento síncrono, sin equipaje global, como diría John Hann, e intenta atender el futuro (en el servidor). Lo que queremos decir con esto es que como CJS soporta módulos sin envoltura, puede sentirse un poco más cerca de las especificaciones de ES.next/Harmony, liberándose de la envoltura define() que impone AMD. Los módulos CJS, sin embargo, sólo soportan objetos como módulos.

Aunque la idea de otro formato de módulo puede ser desalentadora, puede que te interesen algunas muestras de trabajo sobre módulos híbridos AMD/CJS y Univeral AMD/CJS.

Formato híbrido AMD básico (John Hann)

Definición de módulos universales AMD/CommonJS (Variación 2, UMDjs)

Extensible UMD Plugins With (Variación por mí mismo y Thomas Davis).

core.js
myExtension.js
;(function ( name, definition ) { var theModule = definition(), hasDefine = typeof define === 'function', hasExports = typeof module !== 'undefined' && module.exports; if ( hasDefine ) { // AMD Module define(theModule); } else if ( hasExports ) { // Node.js Module module.exports = theModule; } else { // Assign to common namespaces or simply the global object (window) // account for for flat-file/global module extensions var obj = null; var namespaces = name.split("."); var scope = (this.jQuery || this.ender || this.$ || this); for (var i = 0; i 
app.js
$(function(){ // the plugin 'core' is exposed under a core namespace in // this example which we first cache var core = $.core; // use then use some of the built-in core functionality to // highlight all divs in the page yellow core.highlightAll(); // access the plugins (extensions) loaded into the 'plugin' // namespace of our core module: // Set the first div in the page to have a green background. core.plugin.setGreen("div:first"); // Here we're making use of the core's 'highlight' method // under the hood from a plugin loaded in after it // Set the last div to the 'errorColor' property defined in // our core module/plugin. If you review the code further down // you'll see how easy it is to consume properties and methods // between the core and other plugins core.plugin.setRed('div:last');});

ES Harmony Modules Of The Future

TC39, el organismo de estándares encargado de definir la sintaxis y la semántica de ECMAScript y sus futuras iteraciones está compuesto por una serie de desarrolladores muy inteligentes. Algunos de estos desarrolladores (como Alex Russell) han seguido de cerca la evolución del uso de JavaScript para el desarrollo a gran escala durante los últimos años y son muy conscientes de la necesidad de mejorar las características del lenguaje para escribir un JS más modular.

Por esta razón, actualmente hay propuestas para una serie de emocionantes adiciones al lenguaje, incluyendo módulos flexibles que pueden trabajar tanto en el cliente como en el servidor, un cargador de módulos y más. En esta sección, le mostraré algunos ejemplos de código de la sintaxis para módulos en ES.next para que pueda tener una idea de lo que está por venir.

Nota: Aunque Harmony todavía está en las fases de propuesta, ya puede probar características (parciales) de ES.next que abordan el soporte nativo para escribir JavaScript modular gracias al compilador Traceur de Google. Para empezar a trabajar con Traceur en menos de un minuto, lee esta guía de inicio. También hay una presentación en la JSConf que vale la pena ver si estás interesado en aprender más sobre el proyecto.

Módulos con importaciones y exportaciones

Si has leído las secciones sobre los módulos AMD y CJS puede que estés familiarizado con el concepto de las dependencias de los módulos (importaciones) y las exportaciones de los módulos (o, la API/variables públicas que permitimos que otros módulos consuman). En ES.next, estos conceptos se han propuesto de una manera un poco más sucinta con dependencias que se especifican utilizando una palabra clave import. export no es muy diferente a lo que podríamos esperar y creo que muchos desarrolladores mirarán el código de abajo e instantáneamente lo "entenderán".

  • las declaraciones de importación enlazan las exportaciones de un módulo como variables locales y pueden ser renombradas para evitar colisiones/conflictos de nombres.
  • las declaraciones de exportación declaran que un enlace local de un módulo es visible externamente de tal manera que otros módulos pueden leer las exportaciones pero no pueden modificarlas. Curiosamente, los módulos pueden exportar módulos hijos, pero no pueden exportar módulos que hayan sido definidos en otro lugar. También puede renombrar las exportaciones para que su nombre externo difiera de sus nombres locales.

Módulos cargados desde fuentes remotas

Las propuestas de módulos también atienden a los módulos que se basan de forma remota (por ejemplo, una envoltura de la API de terceros) lo que simplifica la carga de módulos desde ubicaciones externas. He aquí un ejemplo en el que podemos cargar el módulo que hemos definido anteriormente y utilizarlo:

Propuesta de cargador de módulos

El cargador de módulos propuesto describe una API dinámica para cargar módulos en contextos muy controlados. Las firmas soportadas en el cargador incluyen load( url, moduleInstance, error) para cargar módulos, createModule( object, globalModuleReferences) y otras. Aquí tenemos otro ejemplo en el que cargamos dinámicamente el módulo que definimos inicialmente. Obsérvese que, a diferencia del último ejemplo, en el que hemos cargado un módulo desde una fuente remota, la API del cargador de módulos se adapta mejor a los contextos dinámicos.

Loader.load('http://addyosmani.com/factory/cakes.js', function(cakeFactory){ cakeFactory.oven.makeCupcake('chocolate'); });

Módulos similares a los de CommonJS para el servidor

Para los desarrolladores orientados al servidor, el sistema de módulos propuesto para ES.next no se limita a ver los módulos en el navegador. A continuación, a modo de ejemplo, se puede ver un módulo tipo CJS propuesto para su uso en el servidor:

// io/File.jsexport function open(path) { ... };export function close(hnd) { ... };
module lexer from 'compiler/LexicalHandler';module stdlib from '@std'; //... scan(cmdline) ...

Clases Con Constructores, Getters & Setters

La noción de una clase siempre ha sido un tema polémico con los puristas y hasta ahora nos hemos arreglado o bien volviendo a la naturaleza prototípica de JavaScript o mediante el uso de frameworks o abstracciones que ofrecen la posibilidad de utilizar las definiciones de clase de una forma que desugar al mismo comportamiento prototípico.

En Harmony, las clases vienen como parte del lenguaje junto con los constructores y (finalmente) algún sentido de verdadera privacidad. En los siguientes ejemplos, he incluido algunos comentarios en línea para ayudarte a entender cómo se estructuran las clases, pero también puedes notar la falta de la palabra ‘función’ aquí. No se trata de un error tipográfico: TC39 han estado haciendo un esfuerzo consciente para disminuir nuestro abuso de la palabra clave function para todo y la esperanza es que esto ayudará a simplificar cómo escribimos el código.

class Cake{ // We can define the body of a class' constructor // function by using the keyword 'constructor' followed // by an argument list of public and private declarations. constructor( name, toppings, price, cakeSize ){ public name = name; public cakeSize = cakeSize; public toppings = toppings; private price = price; } // As a part of ES.next's efforts to decrease the unnecessary // use of 'function' for everything, you'll notice that it's // dropped for cases such as the following. Here an identifier // followed by an argument list and a body defines a new method addTopping( topping ){ public(this).toppings.push(topping); } // Getters can be defined by declaring get before // an identifier/method name and a curly body. get allToppings(){ return public(this).toppings; } get qualifiesForDiscount(){ return private(this).price > 5; } // Similar to getters, setters can be defined by using // the 'set' keyword before an identifier set cakeSize( cSize ){ if( cSize 

ES Harmony Conclusions

As you can see, ES.next is coming with some exciting new additions. Although Traceur can be used to an extent to try our such features in the present, remember that it may not be the best idea to plan out your system to use Harmony (just yet). There are risks here such as specifications changing and a potential failure at the cross-browser level (IE9 for example will take a while to die) so your best bets until we have both spec finalization and coverage are AMD (for in-browser modules) and CJS (for those on the server).

Conclusions And Further Reading A Review

In this article we've reviewed several of the options available for writing modular JavaScript using modern module formats. These formats have a number of advantages over using the (classical) module pattern alone including: avoiding a need for developers to create global variables for each module they create, better support for static and dynamic dependency management, improved compatibility with script loaders, better (optional) compatibility for modules on the server and more.

In short, I recommend trying out what's been suggested today as these formats offer a lot of power and flexibility that can help when building applications based on many reusable blocks of functionality.

And that's it for now. If you have further questions about any of the topics covered today, feel free to hit me up on twitter and I'll do my best to help!

Copyright Addy Osmani, 2012. All Rights Reserved.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.