Ohjelmointi

Koodaa JavaScript älykkäästi, modulaarisesti

Jotkut ihmiset näyttävät edelleen yllättyneiltä siitä, että JavaScriptiä pidetään kunnioitettavana, aikuisena ohjelmointikielenä vakavissa sovelluksissa. Itse asiassa JavaScript-kehitys on kypsynyt hienosti jo vuosia, ja modulaarisen kehityksen parhaat käytännöt ovat erinomainen esimerkki.

Modulaarisen koodin kirjoittamisen edut on dokumentoitu hyvin: parempi ylläpidettävyys, monoliittisten tiedostojen välttäminen ja koodin irrottaminen yksiköistä, jotka voidaan testata oikein. Niille teistä, jotka haluavat tarttua nopeasti, tässä on yleisiä käytäntöjä, joita nykyaikaiset JavaScript-kehittäjät käyttävät modulaarisen koodin kirjoittamiseen.

Moduulin kuvio

Aloitetaan perussuunnittelumallista, jota kutsutaan moduulimalliksi. Kuten epäilet, tämä antaa meille mahdollisuuden kirjoittaa koodia modulaarisesti, mikä antaa meille mahdollisuuden suojata annettujen moduulien suorituskonteksti ja paljastaa globaalisti vain se, mitä haluamme paljastaa.

(funktio () {

// 'private' muuttuja

var orderId = 123;

// paljastaa menetelmät ja muuttujat liittämällä ne

// globaalille objektille

window.orderModule = {

getOrderId: funktio () {

// tuonut sinulle sulkemiset

palautusmääräys ID;

}

};

})()

Nimetöntoiminto ilmaus, joka toimii tässä tapauksessa tehtaana, kirjoitetaan ja kutsutaan välittömästi. Nopeuden vuoksi voit siirtää nimenomaisesti muuttujiatoiminto kutsua uudelleen sidomalla nämä muuttujat paikalliseen laajuuteen. Näet tämän joskus myös puolustuksellisena liikkeenä kirjastoissa, jotka tukevat vanhoja selaimia, joissa tietyt arvot (kutenundefined) ovat kirjoitettavia ominaisuuksia.

(funktio (globaali, määrittelemätön) {

// tässä oleva koodi voi käyttää globaalia objektia nopeasti,

// ja 'undefined' on varmasti 'undefined'

// HUOMAUTUS: Nykyaikaisissa selaimissa 'undefined' ei ole kirjoitettavissa,

// mutta se kannattaa pitää mielessä

// kirjoitettaessa koodia vanhoille selaimille.

})(Tämä)

Tämä on vain suunnittelumalli. Tällä tekniikalla modulaarisen JavaScriptin kirjoittamiseen ei tarvitse sisällyttää ylimääräisiä kirjastoja. Riippuvuuksien puute on suuri plus (tai kriittinen tehtävä) joissakin asetuksissa, varsinkin jos kirjoitat kirjastoa. Näet, että suurin osa suosituista kirjastoista käyttää tätä mallia kapseloimaan sisäisiä toimintoja ja muuttujia paljastamalla vain tarvittavat.

Jos kirjoitat hakemusta, tällä lähestymistavalla on kuitenkin muutamia haittoja. Oletetaan, että luot moduulin, joka asettaa muutaman menetelmän käyttöönikkuna. tilaukset. Jos haluat käyttää näitä menetelmiä sovelluksen muissa osissa, sinun on varmistettava, että moduuli on mukana, ennen kuin soitat niihin. Sitten koodissa, johon soitatwindow.orders.getOrderId, kirjoitat koodin ja toivot, että toinen komentosarja on ladattu.

Tämä ei ehkä näytä olevan maailman loppu, mutta se voi nopeasti nousta hallitsematta monimutkaisissa projekteissa - ja komentosarjojen sisällyttämisjärjestyksen hallinta tulee tuskaksi. Lisäksi kaikki tiedostosi on ladattava synkronisesti, tai voit kutsua kilpailuehdot sisään rikkomaan koodisi. Jos vain olisi tapa ilmoittaa nimenomaisesti moduulit, joita haluat käyttää tietylle koodipitkälle ....

AMD (asynkronisen moduulin määrittely)

AMD syntyi tarpeesta määrittää nimenomaiset riippuvuudet välttäen kaikkien komentosarjojen synkronista lataamista. Sitä on helppo käyttää selaimessa, mutta se ei ole natiivi, joten sinun on sisällytettävä kirjasto, joka lataa komentosarjoja, kuten RequireJS tai curl.js. Moduulin määritteleminen AMD: n avulla näyttää tältä:

// libs / order-module.js

määritä (funktio () {

// 'private' muuttuja

var orderId = 123;

// paljastaa menetelmät ja muuttujat palauttamalla ne

paluu {

getOrderId: funktio () {

palautusmääräys ID;

}

});

Se näyttää samanlaiselta kuin mitä olimme tekemisissä aiemmin, paitsi että sen sijaan, että soittaisimme heti tehdasfunktiomme suoraan, siirrymme argumentiksimääritellä. Todellinen taika alkaa tapahtua, kun haluat käyttää moduulia myöhemmin:

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

orderModule.getOrderId (); // arvioi arvoksi 123

});

Ensimmäinen argumenttimääritellä on nyt joukko riippuvuuksia, jotka voivat olla mielivaltaisesti pitkiä, ja tehdasfunktio listaa niihin liitettävien riippuvuuksien muodolliset parametrit. Jotkut tarvitsemasi riippuvuudet saattavat olla omia riippuvuuksia, mutta AMD: n kanssa sinun ei tarvitse tietää, että:

// src / utils.js

define (['libs / alleviiva'], funktio (_) {

paluu {

moduleId: 'foo',

_ : _

});

// src / myapp.js

määritä ([

'libs / jquery',

'libs / ohjaustanko',

'src / utils'

], function ($, ohjaustanko, apuohjelmat) {

// Käytä kutakin ilmoitettua riippuvuutta ilman

// huolestuttavaa, ovatko he siellä vai eivät.

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

// Alariippuvuudet on myös hoidettu

Käyttää ._. -Näppäimiä (ikkuna);

});

Tämä on loistava tapa kehittää modulaarista JavaScriptiä käsiteltäessä paljon liikkuvia osia ja riippuvuuksia. Vastuu komentosarjojen tilaamisesta ja sisällyttämisestä on nyt komentosarjan latausohjelman harteilla, joten voit vapaasti ilmoittaa tarvitsemasi ja aloittaa sen käytön.

Toisaalta on muutama mahdollinen ongelma. Ensinnäkin sinulla on ylimääräinen kirjasto sisällytettäväksi ja oppia käyttämään. Minulla ei ole kokemusta curl.js: stä, mutta RequireJS sisältää oppimisen kokoonpanon määrittämiseksi projektillesi. Asetusten tunteminen vie tunteja, minkä jälkeen alkuperäisen kokoonpanon kirjoittamisen pitäisi kestää vain minuutteja. Lisäksi moduulimäärittelyt voivat pidentyä, jos ne johtavat kasaan riippuvuuksia. Tässä on esimerkki tämän ongelman selityksestä RequireJS-dokumentaatiossa:

// From RequireJS -dokumentaatio:

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

define (["vaadi", "jquery", "terä / esine", "terä / fn", "rdapi",

"oauth", "blade / jig", "blade / url", "lähetys", "tilit",

"tallennus", "palvelut", "widgetit / AccountPanel", "widgetit / TabButton",

"widgetit / AddAccount", "vähemmän", "osTheme", "jquery-ui-1.8.7.min",

"jquery.textOverflow"],

funktio (vaadi, $, object, fn, rdapi,

oauth, jig, url, lähetys, tilit,

varastointi, palvelut, AccountPanel, TabButton,

Lisää tili, vähemmän, osTheme) {

});

Ai! RequireJS tarjoaa jonkin verran syntaktista sokeria tämän käsittelemiseksi, mikä näyttää melko samanlaiselta kuin toinen suosittu modulaarisen kehityksen sovellusliittymä, CommonJS.

CJS (CommonJS)

Jos olet koskaan kirjoittanut palvelinpuolen JavaScriptiä Node.js: n avulla, olet käyttänyt CommonJS-moduuleja. Jokaista kirjoittamaasi tiedostoa ei ole kääritty mihinkään hienoon, mutta sillä on pääsy muuttujaan nimeltävienti johon voit määrittää mitä tahansa moduulin altistumista. Tältä näyttää:

// 'yksityinen' muuttuja

var orderId = 123;

export.getOrderId = funktio () {

palautusmääräys ID;

};

Sitten, kun haluat käyttää moduulia, ilmoitat sen inline:

// orderModule saa viennin arvon

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

orderModule.getOrderId (); // arvioi arvoksi 123

Syntaktisesti tämä on aina näyttänyt minulle paremmalta, lähinnä siksi, että siihen ei sisälly tuhlaavaa sisennystä muissa keskustelemissamme vaihtoehdoissa. Toisaalta se eroaa suuresti muista, sillä se on suunniteltu riippuvuuksien synkroniseen lataamiseen. Tämä on järkevämpää palvelimella, mutta ei tehdä käyttöliittymässä. Synkroninen riippuvuuden lataus tarkoittaa pidempiä sivun latausaikoja, mikä ei ole hyväksyttävää Webille. Vaikka CJS on ylivoimaisesti suosikkini näköinen moduulisyntaksi, saan sen käyttää vain palvelimella (ja kirjoittaessani mobiilisovelluksia Appceleratorin Titanium Studion kanssa).

Yksi hallitsemaan heitä kaikkia

Nykyinen luonnos kuudennesta ECMAScript-versiosta (ES6), spesifikaatio, josta JavaScripti on toteutettu, lisää moduulien alkuperäisen tuen. Tekniset tiedot ovat edelleen luonnosmuodossa, mutta kannattaa kurkistaa, miltä moduulikehityksen tulevaisuus voisi näyttää. ES6-spesifikaatioissa (tunnetaan myös nimellä Harmony) käytetään melko paljon uusia avainsanoja, joista useita käytetään moduulien kanssa:

// libs / order-module.js

var orderId = 123;

export var getOrderId = function () {

palautusmääräys ID;

};

Voit soittaa myöhemmin myöhemmin useilla tavoilla:

tuo {getOrderId} tiedostosta "libs / order-module";

getOrderId ();

Yllä valitset ja valitset, mikä vienti moduulissa haluat sitoa paikallisiin muuttujiin. Vaihtoehtoisesti voit tuoda koko moduulin ikään kuin se olisi objekti (samanlainen kuinvienti CJS-moduuleissa):

tuo "libs / order-module" orderModule-muotoon;

orderModule.getOrderId ();

ES6-moduuleissa on paljon enemmän (katso lisätietoja Dr.Axel Rauschmayerin 2ality-blogista), mutta esimerkin pitäisi näyttää sinulle muutamia asioita. Ensinnäkin, meillä on syntaksi, joka on samanlainen kuin CJS-moduulit, mikä tarkoittaa, että ylimääräistä sisennystä ei löydy missään, vaikka se ei aina ole, kuten yllä olevasta 2ality-linkistä löydät. Mikä ei ole selvää tarkastelemalla esimerkkiä, varsinkin koska se näyttää niin paljon CJS: ltä, on se, että tuontilausekkeessa luetellut moduulit ladataan asynkronisesti.

Lopputulos on CJS: n helposti luettava syntaksin sekoitus AMD: n asynkronisen luonteen kanssa. Valitettavasti kestää jonkin aikaa, ennen kuin niitä tuetaan täysimääräisesti kaikissa yleisesti kohdistetuissa selaimissa. Siitä lähtien "jonkin aikaa" on kasvanut yhä lyhyemmäksi, kun selaimen toimittajat kiristävät julkaisusykliään.

Nykyään näiden työkalujen yhdistelmä on oikea tapa edetä modulaarisen JavaScript-kehityksen suhteen. Kaikki riippuu siitä, mitä olet tekemässä. Jos kirjoitat kirjastoa, käytä moduulin suunnittelumallia. Jos rakennat sovelluksia selaimelle, käytä AMD-moduuleja komentosarjalataimen kanssa. Jos olet palvelimella, hyödynnä CJS-moduuleja. Lopulta tietysti tuetaan ES6: ta kaikkialla - missä vaiheessa voit tehdä asioita ES6: lla ja romuttaa loput!

Kysymyksiä tai ajatuksia? Jätä vapaasti viesti alla olevaan kommenttiosioon tai ota yhteyttä minuun Twitterissä @ freethejazz.

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