Programování

Kódujte v JavaScriptu chytře, modulárně

Někteří lidé se stále zdají překvapeni, že JavaScript je považován za slušný dospělý programovací jazyk pro seriózní aplikace. Ve skutečnosti vývoj JavaScriptu pěkně dozrává už léta, příkladem jsou osvědčené postupy pro modulární vývoj.

Výhody zápisu modulárního kódu jsou dobře zdokumentovány: větší udržovatelnost, vyhýbání se monolitickým souborům a oddělení kódu do jednotek, které lze správně otestovat. Pro ty z vás, kteří by se chtěli rychle chytit, jsou zde běžné postupy, které moderní vývojáři JavaScriptu používají k psaní modularizovaného kódu.

Vzor modulu

Začněme základním návrhovým vzorem, který se nazývá vzor modulu. Jak můžete předpokládat, umožňuje nám to psát kód modulárním způsobem, což nám umožňuje chránit kontext provádění daných modulů a globálně vystavovat pouze to, co chceme vystavit. Vzor vypadá nějak takto:

(funkce(){

// proměnná „soukromá“

var orderId = 123;

// vystavení metod a proměnných jejich připojením

// na globální objekt

window.orderModule = {

getOrderId: funkce () {

// přináší vám uzávěry

vrátit ID objednávky;

}

};

})()

Anonymnífunkce výraz, který v tomto případě funguje jako továrna, je napsán a volán okamžitě. Pro rychlost můžete explicitně předat proměnné dofunkce volání, účinně rebinding tyto proměnné k místnímu rozsahu. Toto také někdy uvidíte jako obranný manévr v knihovnách podporujících staré prohlížeče, kde jsou určité hodnoty (napřnedefinováno) jsou zapisovatelné vlastnosti.

(funkce (globální, nedefinováno) {

// kód zde umožňuje rychlý přístup k globálnímu objektu,

// a „undefined“ bude určitě „undefined“

// POZNÁMKA: V moderních prohlížečích nelze „undefined“ zapisovat,

// ale stojí za to to mít na paměti

// při psaní kódu pro staré prohlížeče.

})(tento)

Toto je jen designový vzor. S touto technikou, abyste mohli psát modulární JavaScript, nemusíte zahrnovat další knihovny. Nedostatek závislostí je v některých nastaveních velkým plusem (nebo kritickým úkolem), zvláště pokud píšete knihovnu. Uvidíte, že většina populárních knihoven použije tento vzor k zapouzdření interních funkcí a proměnných a odhalí pouze to, co je nutné.

Pokud však píšete aplikaci, má tento přístup několik nevýhod. Řekněme, že vytvoříte modul, který nastaví několik metodokno. objednávky. Pokud chcete tyto metody použít v jiných částech aplikace, musíte se ujistit, že je modul zahrnut, než je zavoláte. Pak v kódu, kam volátewindow.orders.getOrderId, napíšete kód a doufáte, že se načetl druhý skript.

To se nemusí zdát jako konec světa, ale na komplikovaných projektech se to může rychle vymknout kontrole - a správa pořadí zahrnutí skriptu bude bolestivá. Všechny vaše soubory musí být také synchronně načteny, jinak pozvete závodní podmínky, aby váš kód rozbily. Kéž by existoval způsob, jak explicitně deklarovat moduly, které jste chtěli použít pro daný bit kódu ....

AMD (definice asynchronního modulu)

AMD se zrodilo z potřeby specifikovat explicitní závislosti a zároveň se vyhnout synchronnímu načítání všech skriptů. Je to snadné v prohlížeči, ale není to nativní, takže musíte zahrnout knihovnu, která načítá skripty, jako je RequireJS nebo curl.js. Takto vypadá definování modulu pomocí AMD:

// libs / order-module.js

definovat (funkce () {

// proměnná „soukromá“

var orderId = 123;

// vystavit metody a proměnné jejich vrácením

vrátit se {

getOrderId: funkce () {

vrátit ID objednávky;

}

});

Vypadá to podobně jako předtím, až na to, že místo okamžitého přímého volání naší tovární funkce předáváme jako argumentdefinovat. Skutečné kouzlo se začne dít, až budete modul později chtít použít:

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

orderModule.getOrderId (); // vyhodnotí se jako 123

});

První argumentdefinovat je nyní pole závislostí, které může být libovolně dlouhé, a tovární funkce uvádí formální parametry pro tyto závislosti, které k němu mají být připojeny. Některé závislosti, které potřebujete, mohou mít vlastní závislosti, ale u AMD to nemusíte vědět:

// src / utils.js

define (['libs / podtržítko'], funkce (_) {

vrátit se {

moduleId: 'foo',

_ : _

});

// src / myapp.js

definovat ([

'libs / jquery',

'libs / řídítka',

'src / utils'

], funkce ($, řídítka, nástroje) {

// Použijte každou z uvedených závislostí bez

// starosti, jestli tam jsou nebo ne.

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

// Byly také vyřízeny dílčí závislosti

Utils ._. Klíče (okno);

});

Je to skvělý způsob, jak vyvinout modulární JavaScript, když se zabýváte mnoha pohyblivými částmi a závislostmi. Odpovědnost za objednání a zahrnutí skriptů je nyní na bedrech skriptového zavaděče, takže můžete jednoduše říci, co potřebujete, a začít to používat.

Na druhou stranu existuje několik potenciálních problémů. Nejprve musíte přidat další knihovnu a naučit se ji používat. Nemám žádné zkušenosti s curl.js, ale RequireJS zahrnuje učení, jak nastavit konfiguraci pro váš projekt. Bude to trvat několik hodin, než se seznámíte s nastavením, po kterém by zápis počáteční konfigurace měl trvat pouhé minuty. Také definice modulů mohou být zdlouhavé, pokud povedou k hromadě závislostí. Zde je příklad převzatý z vysvětlení tohoto problému v dokumentaci RequireJS:

// Z dokumentace 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", "méně", "osTheme", "jquery-ui-1.8.7.min",

"jquery.textOverflow"],

funkce (require, $, object, fn, rdapi,

oauth, jig, url, odeslání, účty,

úložiště, služby, AccountPanel, TabButton,

AddAccount, méně, osTheme) {

});

Au! RequireJS poskytuje nějaký syntaktický cukr, který se s tím vypořádá, což vypadá docela podobně jako další populární API pro modulární vývoj, CommonJS.

CJS (CommonJS)

Pokud jste někdy psali JavaScript na straně serveru pomocí Node.js, použili jste moduly CommonJS. Každý soubor, který napíšete, není zabalen do ničeho fantastického, ale má přístup k proměnné s názvemvývoz ke kterému můžete přiřadit cokoli, co chcete, aby vám modul vystavil. Vypadá to takto:

// proměnná „soukromá“

var orderId = 123;

exports.getOrderId = funkce () {

vrátit ID objednávky;

};

Pak, když chcete modul použít, prohlásíte jej inline:

// orderModule získá hodnotu 'exportů'

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

orderModule.getOrderId (); // vyhodnotí se jako 123

Syntakticky to pro mě vždy vypadalo lépe, hlavně proto, že to nezahrnuje zbytečné odsazení přítomné v dalších možnostech, o kterých jsme diskutovali. Na druhou stranu se výrazně liší od ostatních v tom, že je navržen pro synchronní načítání závislostí. To dává větší smysl na serveru, ale nebude to dělat na frontendu. Načítání synchronní závislosti znamená delší dobu načítání stránky, což je pro web nepřijatelné. Zatímco CJS je zdaleka moje oblíbená syntaxe modulu, používám ji pouze na serveru (a při psaní mobilních aplikací pomocí aplikace Titanium Studio od Appcelerator).

Jeden, který vládne všem

Aktuální návrh šestého vydání ECMAScript (ES6), specifikace, ze které je implementován JavaScript, přidává nativní podporu modulů. Specifikace je stále ve formě konceptu, ale stojí za to nahlédnout, jak by mohla vypadat budoucnost modulárního vývoje. Ve specifikaci ES6 (také známé jako Harmony) je použito několik nových klíčových slov, z nichž několik se používá u modulů:

// libs / order-module.js

var orderId = 123;

export var getOrderId = funkce () {

vrátit ID objednávky;

};

Později jej můžete zavolat několika způsoby:

importovat {getOrderId} z "libs / order-module";

getOrderId ();

Nahoře vyberete a vyberete, které exporty v rámci modulu chcete svázat s místními proměnnými. Alternativně můžete importovat celý modul, jako by to byl objekt (podobně jakovývoz objekt v modulech CJS):

importovat "libs / order-module" jako orderModule;

orderModule.getOrderId ();

V modulech ES6 je toho mnohem víc (více najdete v blogu 2ality Dr. Axela Rauschmayera), ale příklad by vám měl ukázat několik věcí. Nejprve máme syntaxi podobnou modulům CJS, což znamená, že nikde nenajdete další odsazení, i když tomu tak není vždy, jak najdete v odkazu 2ality výše. Při pohledu na příklad není zřejmé, zejména proto, že vypadá podobně jako CJS, je to, že moduly uvedené v příkazu import jsou načítány asynchronně.

Konečným výsledkem je snadno čitelná syntaxe CJS smíchaná s asynchronní povahou AMD. Bohužel bude chvíli trvat, než budou plně podporovány ve všech běžně cílených prohlížečích. To znamená, že „chvíli“ roste čím dál tím méně, protože prodejci prohlížečů zpřísňují své cykly vydání.

Dnes je kombinace těchto nástrojů způsob, jak jít, pokud jde o modulární vývoj JavaScriptu. Vše záleží na tom, co děláte. Pokud píšete knihovnu, použijte návrhový vzor modulu. Pokud vytváříte aplikace pro prohlížeč, použijte moduly AMD se zavaděčem skriptů. Pokud jste na serveru, využijte výhod modulů CJS. Nakonec bude samozřejmě ES6 podporován plošně - v tom okamžiku můžete dělat věci způsobem ES6 a zbytek zrušit!

Dotazy nebo myšlenky? Neváhejte zanechat zprávu níže v sekci komentářů nebo mě kontaktovat na Twitteru, @ freethejazz.

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