Scrivere JavaScript modulare con AMD, CommonJS e ES Harmony

Tweet

Modularità L’importanza di disaccoppiare la tua applicazione

Quando diciamo che un’applicazione è modulare, generalmente intendiamo che è composta da un insieme di pezzi di funzionalità distinti e altamente disaccoppiati memorizzati in moduli. Come probabilmente sapete, l’accoppiamento lasco facilita la manutenibilità delle applicazioni rimuovendo le dipendenze dove possibile. Quando questo è implementato in modo efficiente, è abbastanza facile vedere come le modifiche ad una parte di un sistema possano influenzarne un’altra.

A differenza di alcuni linguaggi di programmazione più tradizionali, tuttavia, l’attuale iterazione di JavaScript (ECMA-262) non fornisce agli sviluppatori i mezzi per importare tali moduli di codice in modo pulito e organizzato. È una delle preoccupazioni delle specifiche che non hanno richiesto una grande riflessione fino agli anni più recenti in cui la necessità di applicazioni JavaScript più organizzate è diventata evidente.

Invece, gli sviluppatori al momento sono lasciati a ripiegare su variazioni del modulo o su modelli letterali di oggetti. Con molti di questi, gli script dei moduli sono infilati insieme nel DOM con i namespace descritti da un singolo oggetto globale dove è ancora possibile incorrere in collisioni di nomi nella vostra architettura. Non c’è anche un modo pulito per gestire la gestione delle dipendenze senza uno sforzo manuale o strumenti di terze parti.

Mentre le soluzioni native a questi problemi arriveranno in ES Harmony, la buona notizia è che scrivere JavaScript modulare non è mai stato così facile e si può iniziare a farlo oggi.

In questo articolo, esamineremo tre formati per scrivere JavaScript modulare: AMD, CommonJS e le proposte per la prossima versione di JavaScript, Harmony.

Preludio Una nota sugli Script Loaders

È difficile discutere dei moduli AMD e CommonJS senza parlare dell’elefante nella stanza – gli script loaders. Al momento, il caricamento degli script è un mezzo per raggiungere un obiettivo, quell’obiettivo è un JavaScript modulare che può essere usato nelle applicazioni di oggi – per questo, l’uso di uno script loader compatibile è purtroppo necessario. Al fine di ottenere il massimo da questo articolo, raccomando di acquisire una comprensione di base di come funzionano i popolari strumenti di caricamento degli script in modo che le spiegazioni dei formati dei moduli abbiano senso nel contesto.

Ci sono un certo numero di ottimi caricatori per gestire il caricamento dei moduli nei formati AMD e CJS, ma le mie preferenze personali sono RequireJS e curl.js. Tutorial completi su questi strumenti sono al di fuori dello scopo di questo articolo, ma posso raccomandare di leggere il post di John Hann su curl.js e la documentazione API RequireJS di James Burke per saperne di più.

Da una prospettiva di produzione, l’uso di strumenti di ottimizzazione (come l’ottimizzatore RequireJS) per concatenare gli script è consigliato per la distribuzione quando si lavora con tali moduli. È interessante notare che con lo shim AMD di Almond, RequireJS non ha bisogno di essere installato nel sito distribuito e quello che si potrebbe considerare un caricatore di script può essere facilmente spostato al di fuori dello sviluppo.

Detto questo, James Burke direbbe probabilmente che essere in grado di caricare dinamicamente gli script dopo il caricamento della pagina ha ancora i suoi casi d’uso e RequireJS può aiutare anche in questo. Con queste note in mente, cominciamo.

AMD Un formato per scrivere JavaScript modulare nel browser

L’obiettivo generale del formato AMD (Asynchronous Module Definition) è quello di fornire una soluzione per JavaScript modulare che gli sviluppatori possono utilizzare oggi. È nato dall’esperienza del mondo reale di Dojo usando XHR+eval e i sostenitori di questo formato volevano evitare che qualsiasi soluzione futura soffrisse delle debolezze di quelle del passato.

Il formato del modulo AMD stesso è una proposta per definire moduli in cui sia il modulo che le dipendenze possono essere caricati in modo asincrono. Ha un certo numero di vantaggi distinti tra cui l’essere asincrono e altamente flessibile per natura, il che rimuove lo stretto accoppiamento che si potrebbe comunemente trovare tra il codice e l’identità del modulo. Molti sviluppatori si divertono ad usarlo e lo si potrebbe considerare un affidabile trampolino di lancio verso il sistema di moduli proposto per ES Harmony.

AMD iniziò come una bozza di specifica per un formato di modulo sulla lista CommonJS, ma poiché non fu in grado di raggiungere il pieno consenso, l’ulteriore sviluppo del formato si trasferì al gruppo amdjs.

Oggi è abbracciato da progetti che includono Dojo (1.7), MooTools (2.0), Firebug (1.8) e persino jQuery (1.7). Anche se il termine CommonJS formato AMD è stato visto in natura in alcune occasioni, è meglio riferirsi ad esso solo come AMD o supporto Async Module poiché non tutti i partecipanti alla lista CJS volevano perseguirlo.

Nota: C’è stato un tempo in cui la proposta è stata indicata come Modules Transport/C, tuttavia poiché la specifica non era orientata al trasporto di moduli CJS esistenti, ma piuttosto, per definire i moduli ha avuto più senso scegliere la convenzione di denominazione AMD.

Iniziare con i moduli

I due concetti chiave di cui devi essere consapevole qui sono l’idea di un metodo define per facilitare la definizione dei moduli e un metodo require per gestire il caricamento delle dipendenze. define è usato per definire moduli con o senza nome in base alla proposta usando la seguente firma:

Come potete capire dai commenti in linea, il module_id è un argomento opzionale che è tipicamente richiesto solo quando si usano strumenti di concatenazione non-AMD (ci possono essere anche altri casi limite in cui è utile). Quando questo argomento viene lasciato fuori, chiamiamo il modulo anonimo.

Quando si lavora con moduli anonimi, l’idea dell’identità di un modulo è DRY, rendendo banale evitare la duplicazione di nomi di file e codice. Poiché il codice è più portabile, può essere facilmente spostato in altre posizioni (o in giro per il file-system) senza bisogno di alterare il codice stesso o cambiare il suo ID. Il module_id è equivalente ai percorsi delle cartelle nei pacchetti semplici e quando non è usato nei pacchetti. Gli sviluppatori possono anche eseguire lo stesso codice su più ambienti semplicemente usando un ottimizzatore AMD che funziona con un ambiente CommonJS come r.js.

Tornando alla firma define, l’argomento dependencies rappresenta un array di dipendenze che sono richieste dal modulo che state definendo e il terzo argomento (‘definition function’) è una funzione che viene eseguita per istanziare il vostro modulo. Un modulo barebone potrebbe essere definito come segue:

Comprensione di AMD: define()

require d’altra parte è tipicamente usato per caricare il codice in un file JavaScript di primo livello o all’interno di un modulo se si desidera recuperare dinamicamente le dipendenze. Un esempio del suo utilizzo è:

Comprensione di AMD: require()

Dipendenze caricate dinamicamente

Comprensione di AMD: plugin

Quello che segue è un esempio di definizione di un plugin compatibile con AMD:

Nota: sebbene css! sia incluso per il caricamento delle dipendenze CSS nell’esempio precedente, è importante ricordare che questo approccio ha alcuni inconvenienti come il fatto che non è possibile stabilire quando il CSS è completamente caricato. A seconda di come ci si avvicina alla compilazione, potrebbe anche risultare che i CSS siano inclusi come dipendenza nel file ottimizzato, quindi usare i CSS come dipendenza caricata in questi casi con cautela.

Carico dei moduli AMD usando require.js

Carico dei moduli AMD usando curl.js

Moduli con dipendenze differite

Perché AMD è una scelta migliore per scrivere JavaScript modulare?

  • Fornisce una proposta chiara su come approcciare la definizione di moduli flessibili.
  • Significativamente più pulito delle attuali soluzioni di spazio dei nomi globale e tag <script> su cui molti di noi fanno affidamento. C’è un modo pulito per dichiarare i moduli indipendenti e le dipendenze che possono avere.
  • Le definizioni dei moduli sono incapsulate, aiutandoci ad evitare l’inquinamento dello spazio dei nomi globale.
  • Funziona meglio di alcune soluzioni alternative (ad esempio CommonJS, che vedremo a breve). Non ha problemi di cross-domain, locale o di debugging e non dipende da strumenti lato server da utilizzare. La maggior parte dei caricatori AMD supporta il caricamento dei moduli nel browser senza un processo di compilazione.
  • Fornisce un approccio di ‘trasporto’ per includere più moduli in un singolo file. Altri approcci come CommonJS devono ancora accordarsi su un formato di trasporto.
  • È possibile caricare pigramente gli script se questo è necessario.

Moduli AMD con Dojo

Definire moduli compatibili con AMD usando Dojo è abbastanza semplice. Come sopra, definire qualsiasi dipendenza del modulo in un array come primo argomento e fornire un callback (factory) che eseguirà il modulo una volta che le dipendenze sono state caricate.g:

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

Nota la natura anonima del modulo che ora può essere sia consumato da un caricatore asincrono Dojo, RequireJS o il caricatore di moduli standard dojo.require() che potresti essere abituato ad usare.

Per coloro che si stanno chiedendo del referenziamento dei moduli, ci sono alcuni gotchas interessanti che sono utili da sapere qui. Sebbene il modo raccomandato da AMD di referenziare i moduli li dichiari nella lista delle dipendenze con un insieme di argomenti corrispondenti, questo non è supportato dal sistema di compilazione di Dojo 1.6 – funziona davvero solo per i caricatori compatibili con AMD.g:

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

Questo ha molti vantaggi rispetto al namespacing annidato in quanto i moduli non hanno più bisogno di fare riferimento direttamente a interi namespaces ogni volta – tutto ciò di cui abbiamo bisogno è il percorso ‘dojo/cookie’ nelle dipendenze, che una volta alias ad un argomento, può essere referenziato da quella variabile. Questo rimuove la necessità di digitare ripetutamente ‘dojo.’ nelle vostre applicazioni.

Nota: Anche se Dojo 1.6 non supporta ufficialmente i moduli AMD basati sull’utente (né il caricamento asincrono), è possibile farlo funzionare con Dojo usando un certo numero di diversi caricatori di script. Al momento, tutti i moduli Dojo core e Dijit sono stati trasformati alla sintassi AMD e il supporto globale AMD migliorato arriverà probabilmente tra la 1.7 e la 2.0.

L’ultimo intoppo di cui essere consapevoli è che se si desidera continuare ad utilizzare il sistema di compilazione di Dojo o si desidera migrare i moduli più vecchi a questo nuovo stile AMD, la seguente versione più verbosa consente una migrazione più facile. Notate che anche dojo e dijit sono referenziati come dipendenze:

AMD Module Design Patterns (Dojo)

Se avete seguito uno dei miei post precedenti sui benefici dei design pattern, saprete che possono essere molto efficaci nel migliorare il modo in cui ci avviciniamo alla strutturazione di soluzioni a problemi di sviluppo comuni. John Hann ha recentemente fatto un’eccellente presentazione sui design pattern dei moduli AMD che coprono Singleton, Decorator, Mediator e altri. Consiglio vivamente di controllare le sue diapositive se ne avete la possibilità.

Alcuni esempi di questi pattern possono essere trovati qui sotto:

Modello Decorator:

Modello adattatore

Moduli AMD con jQuery

Le basi

A differenza di Dojo, jQuery viene fornito con un solo file, tuttavia data la natura basata su plugin della libreria, possiamo dimostrare come sia semplice definire un modulo AMD che lo usi qui sotto.

C’è comunque qualcosa che manca in questo esempio ed è il concetto di registrazione.

Registrare jQuery come un modulo asincrono compatibile

Una delle caratteristiche chiave che è arrivata in jQuery 1.7 è il supporto per registrare jQuery come un modulo asincrono. Ci sono un certo numero di caricatori di script compatibili (inclusi RequireJS e curl) che sono in grado di caricare i moduli usando un formato di modulo asincrono e questo significa che sono necessari meno hack per far funzionare le cose.

Come risultato della popolarità di jQuery, i caricatori di AMD hanno bisogno di tenere in considerazione versioni multiple della libreria che vengono caricate nella stessa pagina, poiché idealmente non si vuole che diverse versioni diverse vengano caricate allo stesso tempo. I caricatori hanno la possibilità di prendere in considerazione questo problema in modo specifico o di istruire i loro utenti che ci sono problemi noti con gli script di terze parti e le loro librerie.

Quello che l’aggiunta 1.7 porta sul tavolo è che aiuta ad evitare problemi con altro codice di terze parti su una pagina che carica accidentalmente una versione di jQuery sulla pagina che il proprietario non si aspettava. Non si vuole che altre istanze blocchino la propria e quindi questo può essere di beneficio.

Il modo in cui funziona è che lo script loader impiegato indica che supporta versioni multiple di jQuery specificando che una proprietà, define.amd.jQuery è uguale a true. Per coloro che sono interessati a dettagli di implementazione più specifici, registriamo jQuery come un modulo con nome poiché c’è il rischio che possa essere concatenato con altri file che possono usare il metodo define() di AMD, ma non usare uno script di concatenazione adeguato che comprenda le definizioni anonime dei moduli AMD.

Il nome AMD fornisce una coperta di sicurezza che è sia robusta che sicura per la maggior parte dei casi d’uso.

Plugin jQuery più intelligenti

Ho recentemente discusso alcune idee ed esempi di come i plugin jQuery potrebbero essere scritti usando i modelli Universal Module Definition (UMD) qui. Gli UMD definiscono moduli che possono funzionare sia sul client che sul server, così come con tutti i più popolari caricatori di script disponibili al momento. Mentre questa è ancora una nuova area con molti concetti ancora in via di definizione, sentitevi liberi di guardare gli esempi di codice nel titolo della sezione AMD && CommonJS qui sotto e fatemi sapere se pensate che ci sia qualcosa che potremmo fare meglio.

Quali Script Loaders & Frameworks supportano AMD?

In-browser:
Server-side:
  • RequireJS http://requirejs.org
  • PINF http://github.com/pinf/loader-js

Conclusioni AMD

Questi sono esempi molto banali di quanto possano essere utili i moduli AMD, ma spero che forniscano una base per capire come funzionano.

Potreste essere interessati a sapere che molte grandi applicazioni e aziende visibili utilizzano attualmente i moduli AMD come parte della loro architettura. Questi includono IBM e BBC iPlayer, che evidenziano quanto seriamente questo formato sia considerato dagli sviluppatori a livello aziendale.

Per ulteriori motivi per cui molti sviluppatori stanno scegliendo di utilizzare i moduli AMD nelle loro applicazioni, potreste essere interessati a questo post di James Burke.

CommonJS Un formato di modulo ottimizzato per il server

CommonJS è un gruppo di lavoro volontario che mira a progettare, prototipare e standardizzare le API JavaScript. Finora hanno tentato di ratificare gli standard sia per i moduli che per i pacchetti. La proposta del modulo CommonJS specifica una semplice API per dichiarare i moduli lato server e, a differenza di AMD, tenta di coprire un insieme più ampio di preoccupazioni come io, filesystem, promesse e altro.

Inizio

Da un punto di vista strutturale, un modulo CJS è un pezzo riutilizzabile di JavaScript che esporta oggetti specifici resi disponibili a qualsiasi codice dipendente – non ci sono tipicamente wrapper di funzioni intorno a tali moduli (quindi non vedrete define usato qui per esempio).

Ad alto livello contengono fondamentalmente due parti principali: una variabile libera chiamata exports che contiene gli oggetti che un modulo vuole rendere disponibili ad altri moduli e una funzione require che i moduli possono usare per importare le esportazioni di altri moduli.

Comprensione di CJS: require() e exports

Consumo di base delle esportazioni

Equivalente AMD del primo esempio di CJS

Consumo di dipendenze multiple

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

Quali caricatori & Framework supportano CJS?

In-browser:
  • curl.js http://github.com/unscriptable/curl
  • SproutCore 1.1 http://sproutcore.com
  • PINF http://github.com/pinf/loader-js
  • (e altro)
Server-side:

Il CJS è adatto al browser?

Ci sono sviluppatori che ritengono che CommonJS sia più adatto allo sviluppo lato server, che è uno dei motivi per cui c’è attualmente un livello di disaccordo su quale formato dovrebbe essere usato come standard de facto nell’era pre-Harmony, andando avanti. Alcuni degli argomenti contro CJS includono una nota che molte API di CommonJS affrontano caratteristiche orientate al server che uno semplicemente non sarebbe in grado di implementare a livello di browser in JavaScript – per esempio, io, system e js potrebbero essere considerati non implementabili per la natura della loro funzionalità.

Detto questo, è utile sapere come strutturare i moduli CJS a prescindere in modo che possiamo apprezzare meglio come si adattano quando si definiscono moduli che possono essere utilizzati ovunque. I moduli che hanno applicazioni sia sul client che sul server includono motori di validazione, conversione e templating. Il modo in cui alcuni sviluppatori stanno affrontando la scelta del formato da usare è optare per CJS quando un modulo può essere usato in un ambiente lato server e usare AMD se questo non è il caso.

Poiché i moduli AMD sono in grado di usare plugin e possono definire cose più granulari come costruttori e funzioni, questo ha senso. I moduli CJS sono solo in grado di definire oggetti che possono essere noiosi da lavorare se si sta cercando di ottenere costruttori da essi.

Anche se va oltre lo scopo di questo articolo, potreste anche aver notato che sono stati menzionati diversi tipi di metodi ‘require’ quando si discute di AMD e CJS.

La preoccupazione per una convenzione di denominazione simile è ovviamente la confusione e la comunità è attualmente divisa sui meriti di una funzione require globale. Il suggerimento di John Hann qui è che piuttosto che chiamarla ‘require’, che probabilmente non raggiungerebbe l’obiettivo di informare gli utenti sulla differenza tra un global e un inner require, potrebbe avere più senso rinominare il metodo global loader in qualcos’altro (ad esempio il nome della libreria). È per questa ragione che un caricatore come curl.js usa curl() invece di require.

AMD && CommonJS Standard concorrenti, ma ugualmente validi

Mentre questo articolo ha posto maggiore enfasi sull’uso di AMD rispetto a CJS, la realtà è che entrambi i formati sono validi e hanno un uso.

AMD adotta un approccio browser-first allo sviluppo, optando per un comportamento asincrono e una compatibilità semplificata all’indietro, ma non ha alcun concetto di File I/O. Supporta oggetti, funzioni, costruttori, stringhe, JSON e molti altri tipi di moduli, eseguiti nativamente nel browser. È incredibilmente flessibile.

CommonJS d’altra parte ha un approccio server-first, assumendo un comportamento sincrono, nessun bagaglio globale come lo definirebbe John Hann e cerca di provvedere al futuro (sul server). Ciò che intendiamo con questo è che poiché CJS supporta moduli non avvolti, può sentirsi un po’ più vicino alle specifiche ES.next/Harmony, liberandovi dal wrapper define() che AMD impone. I moduli CJS comunque supportano solo oggetti come moduli.

Anche se l’idea di un altro formato di modulo può essere scoraggiante, potresti essere interessato ad alcuni esempi di lavoro sui moduli ibridi AMD/CJS e Univeral AMD/CJS.

Basic AMD Hybrid Format (John Hann)

AMD/CommonJS Universal Module Definition (Variation 2, UMDjs)

Extensible UMD Plugins With (Variation by myself and 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, il corpo standard incaricato di definire la sintassi e la semantica di ECMAScript e le sue future iterazioni è composto da un numero di sviluppatori molto intelligenti. Alcuni di questi sviluppatori (come Alex Russell) hanno tenuto d'occhio l'evoluzione dell'uso di JavaScript per lo sviluppo su larga scala negli ultimi anni e sono acutamente consapevoli della necessità di migliori caratteristiche del linguaggio per scrivere JS più modulare.

Per questa ragione, ci sono attualmente proposte per una serie di eccitanti aggiunte al linguaggio, inclusi moduli flessibili che possono lavorare sia sul client che sul server, un caricatore di moduli e altro. In questa sezione, vi mostrerò alcuni esempi di codice della sintassi per i moduli in ES.next in modo che possiate avere un assaggio di ciò che verrà.

Nota: Anche se Harmony è ancora in fase di proposta, potete già provare le caratteristiche (parziali) di ES.next che riguardano il supporto nativo per scrivere JavaScript modulare grazie al compilatore Traceur di Google. Per essere operativi con Traceur in meno di un minuto, leggete questa guida per iniziare. C'è anche una presentazione JSConf su di esso che vale la pena di guardare se sei interessato a saperne di più sul progetto.

Moduli con importazioni ed esportazioni

Se hai letto le sezioni sui moduli AMD e CJS potresti avere familiarità con il concetto di dipendenze del modulo (importazioni) ed esportazioni del modulo (o, le API pubbliche/variabili che permettiamo ad altri moduli di consumare). In ES.next, questi concetti sono stati proposti in modo leggermente più succinto con le dipendenze che vengono specificate usando una parola chiave import. export non è molto diverso da quello che potremmo aspettarci e penso che molti sviluppatori guarderanno il codice qui sotto e lo "capiranno" immediatamente.

  • le dichiarazioni di importazione legano le esportazioni di un modulo come variabili locali e possono essere rinominate per evitare collisioni/conflitti di nomi.
  • le dichiarazioni di esportazione dichiarano che un local-binding di un modulo è visibile esternamente in modo che altri moduli possono leggere le esportazioni ma non possono modificarle. È interessante notare che i moduli possono esportare moduli figli, ma non possono esportare moduli che sono stati definiti altrove. Puoi anche rinominare le esportazioni in modo che il loro nome esterno differisca dai loro nomi locali.

Moduli caricati da fonti remote

Le proposte di moduli si occupano anche di moduli che sono basati in remoto (ad esempio un wrapper API di terze parti) rendendo semplice il caricamento di moduli da posizioni esterne. Qui c’è un esempio di noi che tiriamo dentro il modulo che abbiamo definito sopra e lo utilizziamo:

Module Loader API

Il caricatore di moduli proposto descrive un’API dinamica per caricare moduli in contesti altamente controllati. Le firme supportate sul caricatore includono load( url, moduleInstance, error) per il caricamento di moduli, createModule( object, globalModuleReferences) e altre. Ecco un altro esempio in cui carichiamo dinamicamente il modulo che abbiamo definito inizialmente. Notate che a differenza dell’ultimo esempio in cui abbiamo tirato dentro un modulo da una fonte remota, l’API del caricatore di moduli è più adatta ai contesti dinamici.

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

Moduli simili a quelli di CommonJS per il server

Per gli sviluppatori che sono orientati al server, il sistema di moduli proposto per ES.next non è solo limitato a guardare i moduli nel browser. Qui sotto, per esempio, potete vedere un modulo simile a CJS proposto per l’uso sul server:

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

Classi con costruttori, getter & setter

La nozione di classe è sempre stata una questione controversa con i puristi e finora ce la siamo cavata ricadendo sulla natura prototipale di JavaScript o usando framework o astrazioni che offrono la possibilità di usare definizioni di classe in una forma che desuggerisce lo stesso comportamento prototipale.

In Harmony, le classi fanno parte del linguaggio insieme ai costruttori e (finalmente) ad un certo senso di vera privacy. Negli esempi seguenti, ho incluso alcuni commenti in linea per aiutarvi a capire come sono strutturate le classi, ma potreste anche notare la mancanza della parola ‘funzione’ qui. Questo non è un errore di battitura: TC39 ha fatto uno sforzo cosciente per diminuire il nostro abuso della parola chiave function per ogni cosa e la speranza è che questo aiuti a semplificare il modo in cui scriviamo il codice.

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.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.