Programovanie

Kódujte v jazyku JavaScript inteligentným a modulárnym spôsobom

Niektorí ľudia sa stále zdajú prekvapení, že sa JavaScript považuje za seriózny a dospelý programovací jazyk pre vážne aplikácie. Vývoj v skutočnosti JavaScript už roky pekne dozrieva, pričom najlepším príkladom sú osvedčené postupy pre modulárny vývoj.

Výhody zápisu modulárneho kódu sú dobre zdokumentované: vyššia udržiavateľnosť, vyhýbanie sa monolitickým súborom a oddelenie kódu od jednotiek, ktoré je možné správne testovať. Pre tých z vás, ktorí by sa chceli rýchlo chytiť, sú tu bežné postupy, ktoré používajú moderní vývojári JavaScriptu na písanie modularizovaného kódu.

Vzor modulu

Začnime základným návrhovým vzorom, ktorý sa nazýva vzor modulu. Ako by ste mohli tušiť, umožňuje nám to písať kód modulárnym spôsobom, čo nám umožňuje chrániť kontext vykonávania daných modulov a globálne vystavovať iba to, čo chceme vystaviť. Vzor vyzerá asi takto:

(funkcia () {

// 'súkromná' premenná

var orderId = 123;

// odkryje metódy a premenné ich pripojením

// ku globálnemu objektu

window.orderModule = {

getOrderId: function () {

// prinesú vám uzávery

vrátiť id objednávky;

}

};

})()

Anonymfunkcia výraz, ktorý v tomto prípade funguje ako továreň, je napísaný a zavolaný okamžite. Pre rýchlosť môžete explicitne odovzdať premenné dofunkcia volanie, ktoré účinne spája tieto premenné s miestnym rozsahom. Toto tiež niekedy uvidíte ako obranný manéver v knižniciach podporujúcich staré prehliadače, kde sú určité hodnoty (naprnedefinované) sú zapisovateľné vlastnosti.

(funkcia (globálna, nedefinovaná) {

// kód tu umožňuje rýchly prístup k globálnemu objektu,

// a „undefined“ bude určite „undefined“

// POZNÁMKA: V moderných prehliadačoch sa na „nedefinované“ nedá zapisovať,

// ale stojí za to mať to na pamäti

// pri písaní kódu pre staré prehliadače.

}) (toto)

Toto je iba dizajnový vzor. S touto technikou nemusíte pri písaní modulárneho JavaScriptu obsahovať ďalšie knižnice. Nedostatok závislostí je veľkým plusom (alebo dôležitým pre misiu) v niektorých nastaveniach, najmä ak píšete knižnicu. Uvidíte, že väčšina populárnych knižníc použije tento vzor na zapuzdrenie vnútorných funkcií a premenných, pričom odhalí iba to, čo je nevyhnutné.

Ak však píšete žiadosť, tento prístup má niekoľko nevýhod. Povedzme, že vytvoríte modul, ktorý nastaví niekoľko metódokno.objednávky. Ak chcete tieto metódy použiť v iných častiach svojej aplikácie, musíte sa uistiť, že je modul predtým, ako im zavoláte, zahrnutý. Potom v kóde, kam volátewindow.orders.getOrderId, napíšete kód a dúfate, že sa načítal druhý skript.

Možno sa to nebude zdať ako koniec sveta, ale pri komplikovaných projektoch sa to môže rýchlo vymknúť spod kontroly - a riadenie poradia zahrnutia skriptu začne byť bolesťou. Všetky vaše súbory musia byť tiež načítané synchrónne, inak pozvete závodné podmienky na rozbitie kódu. Keby len existoval spôsob, ako explicitne deklarovať moduly, ktoré ste chceli použiť pre daný bit kódu ....

AMD (definícia asynchrónneho modulu)

AMD sa zrodilo z potreby špecifikovania explicitných závislostí, aby sa zabránilo synchrónnemu načítaniu všetkých skriptov. Používanie v prehliadači je jednoduché, ale nie je to natívne, takže musíte zahrnúť knižnicu, ktorá načítava skripty, napríklad RequireJS alebo curl.js. Takto vyzerá definovanie modulu pomocou AMD:

// libs / order-module.js

definovať (funkcia () {

// 'súkromná' premenná

var orderId = 123;

// odkryje metódy a premenné ich vrátením

návrat {

getOrderId: function () {

vrátiť id objednávky;

}

});

Vyzerá to podobne, ako sme to riešili predtým, až na to, že namiesto toho, aby sme okamžite zavolali priamo našu továrenskú funkciu, prechádzame ako argumentdefinovať. Skutočné kúzlo sa začne diať, keď budete chcieť modul neskôr použiť:

define (['' libs / order-module '], function (orderModule) {

orderModule.getOrderId (); // vyhodnotí sa na 123

});

Prvý argument zdefinovať je teraz pole závislostí, ktoré môže byť ľubovoľne dlhé, a továrenská funkcia uvádza formálne parametre pre tieto závislosti, ktoré k nemu majú byť pripojené. Niektoré potrebné závislosti teraz môžu mať vlastné závislosti, ale s AMD nemusíte vedieť, že:

// src / utils.js

define (['libs / underscore'], function (_) {

návrat {

moduleId: 'foo',

_ : _

});

// src / myapp.js

definovať ([

'libs / jquery',

„libs / riadidlá“,

„src / utils“

], funkcia ($, riadidlá, pomôcky) {

// Použite každú z uvedených závislostí bez

// obavy, či tam sú alebo nie.

$ ('div'). addClass ('bar');

// Boli tiež postarané o závislosť sub

Utils ._. Kľúče (okno);

});

Je to skvelý spôsob, ako vyvinúť modulárny JavaScript, keď sa zaoberáte množstvom pohyblivých častí a závislostí. Zodpovednosť za objednávanie a zahrnutie skriptov je teraz na pleciach nakladača skriptov, vďaka čomu môžete jednoducho povedať, čo potrebujete, a začať ho používať.

Na druhej strane existuje niekoľko potenciálnych problémov. Najskôr je potrebné zahrnúť ďalšiu knižnicu a naučiť sa ju používať. Nemám skúsenosti s curl.js, ale RequireJS zahŕňa naučenie sa, ako nastaviť konfiguráciu pre váš projekt. Zoznámenie sa s nastaveniami bude trvať niekoľko hodín, potom by úvodná konfigurácia mala trvať iba pár minút. Definície modulov tiež môžu byť zdĺhavé, ak vedú k hromadám závislostí. Tu je príklad prevzatý z vysvetlenia tohto problému v dokumentácii RequireJS:

// Z dokumentácie RequireJS:

// //requirejs.org/docs/whyamd.html#sugar

define (["require", "jquery", "blade / object", "blade / fn", "rdapi",

„oauth“, „blade / jig“, „blade / url“, „send“, „accounts“,

„storage“, „services“, „widgety / AccountPanel“, „widgety / TabButton“,

"widgety / AddAccount", "menej", "osTheme", "jquery-ui-1.8.7.min",

"jquery.textOverflow"],

funkcia (require, $, object, fn, rdapi,

oauth, jig, url, odoslanie, účty,

úložisko, služby, AccountPanel, TabButton,

AddAccount, menej, osTheme) {

});

Au! RequireJS poskytuje na syntézu nejaký syntaktický cukor, ktorý vyzerá dosť podobne ako ďalšie populárne API pre modulárny vývoj, CommonJS.

CJS (CommonJS)

Ak ste niekedy písali JavaScript na strane servera pomocou Node.js, použili ste moduly CommonJS. Každý súbor, ktorý napíšete, nie je zabalený do ničoho fantastického, ale má prístup k premennej s názvomvývoz ku ktorej môžete priradiť čokoľvek, čo chcete, aby vám modul vystavil. Vyzerá to takto:

// „súkromná“ premenná

var orderId = 123;

exports.getOrderId = funkcia () {

vrátiť id objednávky;

};

Ak potom chcete modul použiť, vyhlásite ho za vložený:

// orderModule dostane hodnotu „export“

var orderModule = require ('./ order-module');

orderModule.getOrderId (); // vyhodnotí sa na 123

Syntakticky mi to vždy pripadalo lepšie, hlavne preto, že to nezahŕňa zbytočné odsadenie prítomné v ďalších možnostiach, o ktorých sme hovorili. Na druhej strane sa výrazne líši od ostatných v tom, že je navrhnutý na synchrónne načítanie závislostí. Toto má pre server väčší zmysel, ale pre klientske rozhranie to nebude platiť. Načítanie synchrónnej závislosti znamená dlhšie načítanie stránky, čo je pre web neprijateľné. Zatiaľ čo CJS je zďaleka moja najobľúbenejšia syntax modulu, môžem ho používať iba na serveri (a pri písaní mobilných aplikácií pomocou aplikácie Titanium Studio od Appcelerator).

Jeden, ktorý vládne všetkým

Aktuálny koncept šiesteho vydania ECMAScript (ES6), ktorého špecifikácia je implementovaná v jazyku JavaScript, pridáva natívnu podporu pre moduly. Špecifikácia je stále v podobe konceptu, ale stojí za to nahliadnuť do toho, ako by mohla vyzerať budúcnosť modulárneho vývoja. V špecifikácii ES6 (známej tiež ako Harmony) sa používa pomerne veľa nových kľúčových slov, z ktorých niektoré sa používajú s modulmi:

// libs / order-module.js

var orderId = 123;

export var getOrderId = funkcia () {

vrátiť id objednávky;

};

Môžete to zavolať neskôr niekoľkými spôsobmi:

importovať {getOrderId} z "libs / order-module";

getOrderId ();

Vyššie si vyberáte a vyberáte, ktoré exporty v rámci modulu chcete viazať na lokálne premenné. Prípadne môžete importovať celý modul, akoby to bol objekt (podobne ako v prípadevývoz objekt v moduloch CJS):

importovať "libs / order-module" ako orderModule;

orderModule.getOrderId ();

V moduloch ES6 je toho oveľa viac (ďalšie informácie nájdete v blogu Dr. Axela Rauschmayera o 2ality), ale príklad by vám mal ukázať niekoľko vecí. Najprv máme syntax podobnú modulom CJS, čo znamená, že nikde nie je možné nájsť ďalšie odsadenie, aj keď to tak nie je vždy, ako nájdete vo vyššie uvedenom odkaze 2ality. Pri pohľade na príklad nie je zrejmé, najmä preto, že vyzerá veľmi podobne ako CJS, je to, že moduly uvedené v príkaze na import sa načítajú asynchrónne.

Konečným výsledkom je ľahko čitateľná syntax CJS zmiešaná s asynchrónnou povahou AMD. Bohužiaľ to bude chvíľu trvať, kým budú plne podporované vo všetkých bežne zameraných prehľadávačoch. To znamená, že „čas“ sa čoraz kratšie zväčšoval, keď dodávatelia prehliadačov sprísňovali cykly vydávania.

Dnešná doba predstavuje kombináciu týchto nástrojov, pokiaľ ide o vývoj modulárneho JavaScriptu. Všetko závisí od toho, čo robíte. Ak píšete knižnicu, použite vzor návrhu modulu. Ak vytvárate aplikácie pre prehliadač, použite moduly AMD so zavádzačom skriptov. Ak ste na serveri, využite výhody modulov CJS. Nakoniec bude samozrejme ES6 podporovaný celoplošne - v tom okamihu môžete robiť veci spôsobom ES6 a zvyšok vyhodiť!

Otázky alebo myšlienky? Neváhajte a zanechajte správu nižšie v sekcii komentárov alebo ma kontaktujte na Twitteri @ freethejazz.

$config[zx-auto] not found$config[zx-overlay] not found