Scrierea de JavaScript modular cu AMD, CommonJS & ES Harmony

Tweet

Modularitate Importanța decuplajului aplicației

Când spunem că o aplicație este modulară, ne referim în general la faptul că este compusă dintr-un set de bucăți de funcționalitate distincte, foarte decuplate, stocate în module. După cum probabil știți, cuplarea liberă facilitează întreținerea mai ușoară a aplicațiilor prin eliminarea dependențelor acolo unde este posibil. Atunci când acest lucru este implementat eficient, este destul de ușor de văzut cum modificările aduse unei părți a unui sistem pot afecta o altă parte a acestuia.

Dincolo de unele limbaje de programare mai tradiționale, însă, iterația actuală a JavaScript (ECMA-262) nu oferă dezvoltatorilor mijloacele de a importa astfel de module de cod într-o manieră curată și organizată. Este una dintre preocupările legate de specificațiile care nu au necesitat o mare reflecție până în anii mai recenți, când a devenit evidentă necesitatea unor aplicații JavaScript mai organizate.

În schimb, în prezent, dezvoltatorii sunt nevoiți să recurgă la variații ale modelelor de module sau obiecte literale. Cu multe dintre acestea, scripturile de module sunt înșirate împreună în DOM, spațiile de nume fiind descrise de un singur obiect global, unde este încă posibil să se producă coliziuni de denumire în arhitectura dvs. De asemenea, nu există o modalitate curată de a gestiona gestionarea dependențelor fără un oarecare efort manual sau instrumente terțe.

În timp ce soluțiile native la aceste probleme vor sosi în ES Harmony, vestea bună este că scrierea de JavaScript modular nu a fost niciodată mai ușoară și puteți începe să o faceți de astăzi.

În acest articol, vom analiza trei formate pentru scrierea de JavaScript modular: AMD, CommonJS și propunerile pentru următoarea versiune de JavaScript, Harmony.

Preludiu O notă despre încărcătoarele de script

Este dificil să discutăm despre modulele AMD și CommonJS fără a vorbi despre elefantul din cameră – încărcătoarele de script. În prezent, încărcarea scripturilor este un mijloc pentru atingerea unui scop, acest scop fiind un JavaScript modular care poate fi utilizat în aplicațiile actuale – pentru aceasta, utilizarea unui încărcător de scripturi compatibil este, din păcate, necesară. Pentru a profita la maximum de acest articol, vă recomand să dobândiți o înțelegere de bază a modului în care funcționează instrumentele populare de încărcare a scripturilor, astfel încât explicațiile privind formatele modulelor să aibă sens în context.

Există o serie de încărcătoare excelente pentru a gestiona încărcarea modulelor în formatele AMD și CJS, dar preferințele mele personale sunt RequireJS și curl.js. Tutoriale complete cu privire la aceste instrumente ies din sfera de aplicare a acestui articol, dar vă pot recomanda să citiți postarea lui John Hann despre curl.js și documentația API RequireJS a lui James Burke pentru mai multe informații.

Dintr-o perspectivă de producție, utilizarea instrumentelor de optimizare (cum ar fi optimizatorul RequireJS) pentru concatenarea scripturilor este recomandată pentru implementare atunci când se lucrează cu astfel de module. În mod interesant, cu Almond AMD shim, RequireJS nu trebuie să fie rulat în site-ul implementat și ceea ce ați putea considera un încărcător de scripturi poate fi cu ușurință mutat în afara dezvoltării.

Aceasta spus, James Burke ar spune probabil că a fi capabil să încarci dinamic scripturi după încărcarea paginii are încă cazurile sale de utilizare și RequireJS poate ajuta și în acest sens. Cu aceste note în minte, să începem.

AMD Un format pentru scrierea de JavaScript modular în browser

Obiectivul general pentru formatul AMD (Asynchronous Module Definition) este de a oferi o soluție pentru JavaScript modular pe care dezvoltatorii o pot folosi astăzi. S-a născut din experiența Dojo în lumea reală folosind XHR+eval, iar susținătorii acestui format au vrut să evite ca orice soluție viitoare să sufere de slăbiciunile celor din trecut.

Formul de module AMD în sine este o propunere pentru definirea modulelor în care atât modulul cât și dependențele pot fi încărcate în mod asincron. Acesta are o serie de avantaje distincte, inclusiv faptul că este atât asincron, cât și extrem de flexibil prin natura sa, ceea ce elimină cuplarea strânsă pe care o putem găsi de obicei între cod și identitatea modulului. Mulți dezvoltatori îl folosesc cu plăcere și ar putea fi considerat un punct de plecare fiabil către sistemul de module propus pentru ES Harmony.

AMD a început ca un proiect de specificație pentru un format de modul pe lista CommonJS, dar cum nu a reușit să ajungă la un consens deplin, dezvoltarea ulterioară a formatului s-a mutat în grupul amdjs.

Astăzi este îmbrățișat de proiecte precum Dojo (1.7), MooTools (2.0), Firebug (1.8) și chiar jQuery (1.7). Deși termenul de format CommonJS AMD a fost văzut ocazional în sălbăticie, cel mai bine este să ne referim la el doar ca AMD sau Async Module support, deoarece nu toți participanții de pe lista CJS au dorit să îl urmărească.

Notă: A existat o perioadă în care propunerea a fost denumită Modules Transport/C, însă, deoarece specificația nu era orientată spre transportul modulelor CJS existente, ci mai degrabă spre definirea modulelor, a fost mai logic să se opteze pentru convenția de denumire AMD.

Începând cu modulele

Cele două concepte cheie pe care trebuie să le cunoașteți aici sunt ideea unei metode define pentru a facilita definirea modulelor și o metodă require pentru a gestiona încărcarea dependențelor. define este utilizată pentru a defini modulele numite sau nenumite pe baza propunerii folosind următoarea semnătură:

După cum vă puteți da seama din comentariile inline, module_id este un argument opțional care, de obicei, este necesar doar atunci când se utilizează instrumente de concatenare non-AMD (pot exista și alte cazuri limită în care este util). Atunci când acest argument este omis, numim modulul anonim.

Când lucrăm cu module anonime, ideea de identitate a unui modul este DRY, ceea ce face ca evitarea duplicării numelor de fișiere și a codului să fie trivială. Deoarece codul este mai portabil, acesta poate fi mutat cu ușurință în alte locații (sau în jurul sistemului de fișiere) fără a fi nevoie să se modifice codul în sine sau să se schimbe ID-ul acestuia. module_id este echivalent cu căile de acces la dosare în pachetele simple și atunci când nu este utilizat în pachete. Dezvoltatorii pot, de asemenea, să ruleze același cod pe mai multe medii doar prin utilizarea unui optimizator AMD care funcționează cu un mediu CommonJS, cum ar fi r.js.

Înapoi la semnătura define, argumentul dependencies reprezintă o matrice de dependențe care sunt necesare pentru modulul pe care îl definiți, iar al treilea argument („definition function”) este o funcție care este executată pentru a instanția modulul dumneavoastră. Un modul barebone ar putea fi definit după cum urmează:

Înțelegerea AMD: define()

require, pe de altă parte, este utilizat de obicei pentru a încărca codul într-un fișier JavaScript de nivel superior sau în cadrul unui modul, în cazul în care doriți să preluați în mod dinamic dependențele. Un exemplu de utilizare a acestuia este:

Înțelegând AMD: require()

Dindependențe încărcate dinamic

Înțelegând AMD: plugin-uri

Cel de mai jos este un exemplu de definire a unui plugin compatibil cu AMD:

Notă: Deși css! este inclus pentru încărcarea dependențelor CSS în exemplul de mai sus, este important să ne amintim că această abordare are unele avertismente, cum ar fi faptul că nu este pe deplin posibil să se stabilească momentul în care CSS-ul este complet încărcat. În funcție de modul în care abordați compilarea, aceasta poate avea ca rezultat, de asemenea, includerea CSS ca dependență în fișierul optimizat, deci utilizați CSS ca dependență încărcată în astfel de cazuri cu prudență.

Încărcarea modulelor AMD utilizând require.js

Încărcarea modulelor AMD folosind curl.js

Moduli cu dependențe amânate

De ce este AMD o alegere mai bună pentru scrierea de JavaScript modular?

  • Furnizează o propunere clară pentru modul de abordare a definirii modulelor flexibile.
  • Semnificativ mai curat decât soluțiile actuale de spațiu de nume global și tag-ul <script> pe care mulți dintre noi se bazează. Există o modalitate curată de a declara modulele autonome și dependențele pe care acestea le pot avea.
  • Definițiile modulelor sunt încapsulate, ajutându-ne să evităm poluarea spațiului global de nume.
  • Funcționează mai bine decât unele soluții alternative (de exemplu, CommonJS, pe care îl vom analiza în curând). Nu are probleme cu domeniul încrucișat, locale sau de depanare și nu are o dependență față de instrumentele din partea serverului pentru a fi utilizate. Majoritatea încărcătoarelor AMD suportă încărcarea modulelor în browser fără un proces de construire.
  • Furnizează o abordare de „transport” pentru includerea mai multor module într-un singur fișier. Alte abordări, cum ar fi CommonJS, trebuie încă să cadă de acord asupra unui format de transport.
  • Este posibilă încărcarea leneșă a scripturilor, dacă este necesar.

Moduli AMD cu Dojo

Definirea modulelor compatibile cu AMD folosind Dojo este destul de simplă. Conform celor de mai sus, definiți orice dependențe ale modulului într-un array ca prim argument și furnizați un callback (factory) care va executa modulul odată ce dependențele au fost încărcate. e.g:

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

Rețineți natura anonimă a modulului care acum poate fi consumat atât de un încărcător asincron Dojo, cât și de RequireJS sau de încărcătorul de module standard dojo.require() pe care poate sunteți obișnuiți să îl folosiți.

Pentru cei care se întreabă despre referențierea modulelor, există câteva lucruri interesante care sunt utile de știut aici. Deși modalitatea de referențiere a modulelor recomandată de AMD le declară în lista de dependențe cu un set de argumente corespunzătoare, acest lucru nu este suportat de sistemul de compilare Dojo 1.6 – funcționează cu adevărat doar pentru încărcătoarele compatibile cu AMD. e.g:

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

Acest lucru are multe progrese față de namespacing-ul imbricate, deoarece modulele nu mai trebuie să facă referire directă la spații de nume complete de fiecare dată – tot ce avem nevoie este calea „dojo/cookie” în dependențe, care, odată aliasată la un argument, poate fi menționată de acea variabilă. Acest lucru elimină necesitatea de a tasta în mod repetat ‘dojo.’ în aplicațiile dvs.

Notă: Deși Dojo 1.6 nu suportă în mod oficial modulele AMD bazate pe utilizator (și nici încărcarea asincronă), este posibil să faceți acest lucru să funcționeze cu Dojo folosind un număr de încărcătoare de scripturi diferite. În prezent, toate modulele Dojo de bază și Dijit au fost transformate în sintaxa AMD, iar suportul general îmbunătățit pentru AMD va ateriza probabil între 1.7 și 2.0.

Ultimul obstacol de care trebuie să fiți conștienți este că, dacă doriți să continuați să utilizați sistemul de construcție Dojo sau doriți să migrați modulele mai vechi la acest nou stil AMD, următoarea versiune mai verosimilă permite o migrare mai ușoară. Observați că și dojo și dijit și sunt menționate ca dependențe:

AMD Module Design Patterns (Dojo)

Dacă ați urmărit oricare dintre postările mele anterioare despre beneficiile modelelor de proiectare, veți ști că acestea pot fi foarte eficiente în îmbunătățirea modului în care abordăm structurarea soluțiilor la problemele comune de dezvoltare. John Hann a făcut recent o prezentare excelentă despre modelele de proiectare a modulelor AMD, care acoperă Singleton, Decorator, Mediator și altele. Vă recomand cu căldură să consultați slide-urile sale dacă aveți ocazia.

Câteva exemple ale acestor modele pot fi găsite mai jos:

Modelul Decorator:

Patronul adaptor

Moduli AMD cu jQuery

Noțiuni de bază

În comparație cu Dojo, jQuery vine cu adevărat doar cu un singur fișier, cu toate acestea, având în vedere natura bazată pe plugin-uri a bibliotecii, putem demonstra mai jos cât de simplu este să definim un modul AMD care să îl folosească.

Există totuși ceva care lipsește din acest exemplu și este conceptul de înregistrare.

Înregistrarea jQuery ca un modul compatibil asincron

Una dintre caracteristicile cheie care a aterizat în jQuery 1.7 a fost suportul pentru înregistrarea jQuery ca un modul asincron. Există o serie de încărcătoare de scripturi compatibile (inclusiv RequireJS și curl) care sunt capabile să încarce modulele folosind un format de modul asincron și acest lucru înseamnă că sunt necesare mai puține hack-uri pentru a face lucrurile să funcționeze.

Ca urmare a popularității jQuery, încărcătoarele AMD trebuie să ia în considerare mai multe versiuni ale bibliotecii care sunt încărcate în aceeași pagină, deoarece, în mod ideal, nu doriți ca mai multe versiuni diferite să se încarce în același timp. Încărcătorii au opțiunea fie de a lua în mod specific în considerare această problemă, fie de a-și instrui utilizatorii că există probleme cunoscute cu scripturile terților și bibliotecile lor.

Ce aduce adăugarea 1.7 este că ajută la evitarea problemelor legate de alte coduri terțe de pe o pagină care încarcă accidental o versiune de jQuery în pagină la care proprietarul nu se aștepta. Nu vreți ca alte instanțe să vi le blocheze pe ale voastre și, prin urmare, acest lucru poate fi benefic.

Modul în care funcționează este că încărcătorul de scripturi utilizat indică faptul că acceptă mai multe versiuni jQuery prin specificarea faptului că o proprietate, define.amd.jQuery este egală cu true. Pentru cei interesați de detalii mai specifice de implementare, înregistrăm jQuery ca un modul cu nume, deoarece există riscul ca acesta să fie concatenat cu alte fișiere care pot utiliza metoda define() de la AMD, dar nu folosesc un script de concatenare adecvat care să înțeleagă definițiile modulelor AMD anonime.

Modul AMD numit oferă o pătură de siguranță de a fi atât robust cât și sigur pentru majoritatea cazurilor de utilizare.

Smarter jQuery Plugins

Am discutat recent câteva idei și exemple despre cum ar putea fi scrise plugin-urile jQuery folosind modele Universal Module Definition (UMD) aici. UMD definesc module care pot funcționa atât pe client cât și pe server, precum și cu toate încărcătoarele de scripturi populare disponibile în acest moment. Deși acesta este încă un domeniu nou, cu o mulțime de concepte încă în curs de finalizare, nu ezitați să vă uitați la exemplele de cod din titlul secțiunii AMD && CommonJS de mai jos și anunțați-mă dacă simțiți că există ceva ce am putea face mai bine.

Ce încărcătoare de scripturi & Frameworks suportă AMD?

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

AMD Concluzii

Cele de mai sus sunt exemple foarte banale despre cât de utile pot fi cu adevărat modulele AMD, dar sperăm că oferă o bază pentru a înțelege cum funcționează.

S-ar putea să vă intereseze să știți că multe aplicații și companii mari vizibile folosesc în prezent module AMD ca parte a arhitecturii lor. Printre acestea se numără IBM și BBC iPlayer, care evidențiază cât de serios este luat în considerare acest format de către dezvoltatori la nivel de întreprindere.

Pentru mai multe motive pentru care mulți dezvoltatori aleg să folosească modulele AMD în aplicațiile lor, ați putea fi interesați de această postare a lui James Burke.

CommonJS Un format de module optimizat pentru server

CommonJS sunt un grup de lucru voluntar care are ca scop proiectarea, prototiparea și standardizarea API-urilor JavaScript. Până în prezent au încercat să ratifice standarde atât pentru module cât și pentru pachete. Propunerea de module CommonJS specifică un API simplu pentru declararea modulelor pe partea de server și, spre deosebire de AMD, încearcă să acopere un set mai larg de preocupări, cum ar fi io, sistemul de fișiere, promisiuni și altele.

Începem

Din punct de vedere al structurii, un modul CJS este o bucată reutilizabilă de JavaScript care exportă obiecte specifice puse la dispoziția oricărui cod dependent – de obicei, nu există învelișuri de funcții în jurul unor astfel de module (deci nu veți vedea define folosit aici, de exemplu).

La un nivel înalt, ele conțin în principiu două părți principale: o variabilă liberă numită exports care conține obiectele pe care un modul dorește să le pună la dispoziția altor module și o funcție require pe care modulele o pot folosi pentru a importa exporturile altor module.

Înțelegerea CJS: require() și exporturi

Consumul de bază al exporturilor

Echivalentul AMD al primului exemplu CJS

Consumul de dependențe multiple

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

Ce cadre de încărcare & suportă CJS?

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

Este CJS potrivit pentru browser?

Există dezvoltatori care consideră că CommonJS este mai potrivit pentru dezvoltarea pe server, acesta fiind unul dintre motivele pentru care există în prezent un nivel de dezacord cu privire la formatul care ar trebui să fie și va fi folosit ca standard de facto în epoca pre-Harmony în viitor. Unele dintre argumentele împotriva CJS includ observația că multe API-uri CommonJS abordează caracteristici orientate către server care pur și simplu nu ar putea fi implementate la nivel de browser în JavaScript – de exemplu, io, system și js ar putea fi considerate neimplementabile prin natura funcționalității lor.

Acestea fiind spuse, este util să știm cum se structurează modulele CJS indiferent, astfel încât să putem aprecia mai bine modul în care se potrivesc atunci când definim module care pot fi folosite peste tot. Printre modulele care au aplicații atât pe client cât și pe server se numără motoarele de validare, de conversie și de modelare. Modul în care unii dezvoltatori abordează alegerea formatului de utilizat este de a opta pentru CJS atunci când un modul poate fi utilizat într-un mediu server-side și de a utiliza AMD dacă nu este cazul.

Deoarece modulele AMD sunt capabile să utilizeze plugin-uri și pot defini lucruri mai granulare, cum ar fi constructori și funcții, acest lucru are sens. Modulele CJS sunt capabile să definească doar obiecte, ceea ce poate fi plictisitor să lucrezi cu ele dacă încerci să obții constructori din ele.

Deși depășește sfera de aplicare a acestui articol, poate ați observat, de asemenea, că au fost menționate diferite tipuri de metode „require” atunci când s-a discutat despre AMD și CJS.

Preocuparea cu o convenție de denumire similară este, desigur, confuzia, iar comunitatea este în prezent împărțită în ceea ce privește meritele unei funcții „require” globale. Sugestia lui John Hann aici este că, mai degrabă decât să o numim „require”, ceea ce probabil nu ar reuși să atingă scopul de a informa utilizatorii despre diferența dintre un global și un inner require, ar putea fi mai logic să redenumim metoda global loader în alt mod (de exemplu, numele bibliotecii). Acesta este motivul pentru care un încărcător precum curl.js folosește curl(), spre deosebire de require.

AMD && CommonJS Standarde concurente, dar la fel de valabile

În timp ce acest articol a pus mai mult accent pe utilizarea AMD față de CJS, realitatea este că ambele formate sunt valabile și au o utilizare.

AMD adoptă o abordare a dezvoltării bazată mai întâi pe browser, optând pentru un comportament asincron și o compatibilitate retroactivă simplificată, dar nu are niciun concept de File I/O. Acesta suportă obiecte, funcții, constructori, șiruri de caractere, JSON și multe alte tipuri de module, care rulează nativ în browser. Este incredibil de flexibil.

CommonJS, pe de altă parte, are o abordare server-first, presupunând un comportament sincron, fără bagaj global, așa cum l-ar numi John Hann, și încearcă să se ocupe de viitor (pe server). Ceea ce vrem să spunem prin aceasta este că, deoarece CJS suportă modulele fără înveliș, se poate simți un pic mai aproape de specificațiile ES.next/Harmony, eliberându-vă de învelișul define() pe care AMD îl impune. Cu toate acestea, modulele CJS suportă doar obiecte ca module.

Deși ideea unui alt format de module poate fi descurajantă, ați putea fi interesați de câteva mostre de lucru pe module hibride AMD/CJS și Univeral AMD/CJS.

Formatul hibrid AMD de bază (John Hann)

Definiția modulelor universale AMD/CommonJS (Variația 2, UMDjs)

Plugini UMD extensibile cu (Variație realizată de mine și 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, organismul de standardizare însărcinat cu definirea sintaxei și semanticii ECMAScript și a viitoarelor sale iterații, este compus dintr-un număr de dezvoltatori foarte inteligenți. Unii dintre acești dezvoltatori (cum ar fi Alex Russell) au urmărit îndeaproape evoluția utilizării JavaScript pentru dezvoltarea la scară largă în ultimii ani și sunt foarte conștienți de necesitatea unor caracteristici mai bune ale limbajului pentru scrierea unui JS mai modular.

Din acest motiv, există în prezent propuneri pentru o serie de adăugiri interesante ale limbajului, inclusiv module flexibile care pot funcționa atât pe client, cât și pe server, un încărcător de module și multe altele. În această secțiune, vă voi prezenta câteva mostre de cod ale sintaxei pentru module în ES.next, astfel încât să vă puteți face o idee despre ceea ce va urma.

Notă: Deși Harmony se află încă în fazele de propunere, puteți încerca deja caracteristici (parțiale) ale ES.next care abordează suportul nativ pentru scrierea de JavaScript modular datorită compilatorului Traceur de la Google. Pentru a începe să lucrați cu Traceur în mai puțin de un minut, citiți acest ghid de inițiere. Există, de asemenea, o prezentare JSConf despre acesta care merită să fie consultată dacă sunteți interesat să aflați mai multe despre proiect.

Moduli cu importuri și exporturi

Dacă ați citit secțiunile despre modulele AMD și CJS, este posibil să fiți familiarizat cu conceptul de dependențe de module (importuri) și exporturi de module (sau, API/variabilele publice pe care le permitem altor module să le consume). În ES.next, aceste concepte au fost propuse într-o manieră ceva mai succintă, dependențele fiind specificate cu ajutorul unui cuvânt cheie import. export nu este foarte diferit de ceea ce ne-am putea aștepta și cred că mulți dezvoltatori se vor uita la codul de mai jos și îl vor "înțelege" instantaneu.

  • declarațiile de import leagă exporturile unui modul ca variabile locale și pot fi redenumite pentru a evita coliziunile/conflictele de nume.
  • declarațiile de export declară că o legătură locală a unui modul este vizibilă din exterior, astfel încât alte module pot citi exporturile, dar nu le pot modifica. Interesant este că modulele pot exporta modulele copil, însă nu pot exporta modulele care au fost definite în altă parte. De asemenea, puteți redenumi exporturile astfel încât numele lor extern să fie diferit de numele lor local.

Moduli încărcați din surse la distanță

Propunerile de module se adresează, de asemenea, modulelor care sunt bazate la distanță (de exemplu, un înveliș API de la terți), ceea ce face ca încărcarea modulelor din locații externe să fie simplificată. Iată un exemplu în care introducem modulul pe care l-am definit mai sus și îl utilizăm:

Module Loader API

Module Loader propus descrie un API dinamic pentru încărcarea modulelor în contexte foarte controlate. Semnăturile suportate de încărcător includ load( url, moduleInstance, error) pentru încărcarea modulelor, createModule( object, globalModuleReferences) și altele. Iată un alt exemplu în care încărcăm dinamic modulul pe care l-am definit inițial. Rețineți că, spre deosebire de ultimul exemplu în care am tras un modul dintr-o sursă de la distanță, API-ul de încărcare a modulelor este mai potrivit pentru contexte dinamice.

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

Moduli de tip CommonJS pentru server

Pentru dezvoltatorii care sunt orientați spre server, sistemul de module propus pentru ES.next nu se limitează doar la consultarea modulelor în browser. Mai jos, pentru exemple, puteți vedea un modul de tip CJS propus pentru utilizare pe server:

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

Classe cu constructori, Getters & Setters

Noțiunea de clasă a fost întotdeauna o problemă controversată cu puriștii și până acum ne-am descurcat fie prin revenirea la natura prototipală a JavaScript, fie prin utilizarea de cadre sau abstracțiuni care oferă posibilitatea de a utiliza definiții de clasă într-o formă care desugrăvește același comportament prototipal.

În Harmony, clasele vin ca parte a limbajului, împreună cu constructorii și (în sfârșit) un oarecare sens al adevăratei intimități. În exemplele de mai jos, am inclus câteva comentarii inline pentru a vă ajuta să înțelegeți cum sunt structurate clasele, dar puteți observa, de asemenea, lipsa cuvântului „funcție” aici. Aceasta nu este o greșeală de scriere: TC39 au făcut un efort conștient pentru a diminua abuzul nostru de cuvântul cheie function pentru orice și speranța este că acest lucru va ajuta la simplificarea modului în care scriem codul.

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.

Lasă un răspuns

Adresa ta de email nu va fi publicată.