Datan kapselointi JavaScriptissä: getterit ja setterit
Kun rakennetaan suurempia JavaScript-sovelluksia, ne on pian jaettava moduuleihin, joita yhdistävät selkeät sopimukset. Kun kyseessä on pitkäaikainen ylläpito, on huolehdittava siitä, että yhteensopivuus säilyy käyttöliittymämuutosten yhteydessä. Tätä varten oliosuuntautuneet kielet tukeutuvat kapselointiin eli tietoihin, jotka piilottavat toteutuksen yksityiskohdat koodin käyttäjiltä, jotta se voi muuttua vaikuttamatta asiakkaisiin.
Tässä viestissä puhumme datan kapseloinnista JavaScriptissä. Tarkemmin sanottuna puhumme ominaisuuksien kapseloinnista getterien ja setterien taakse.
Joitakin käsitteitä
JavaScript suunniteltiin pitäen lähtökohtanaan ankkatyypittelyn periaatetta:
“Kun näen linnun, joka kävelee kuin ankka ja ui kuin ankka ja visertää kuin ankka, kutsun tuota lintua ankaksi.”
Muilla sanoilla JavaScript on ytimeltään oliosuuntautunut kieli, mutta toisin kuin muissa oliosuuntautuneissa kielissä, kuten C#:ssa ja Javassa, JavaScriptissä luokat ovat toisen luokan kansalaisia eikä rajapintoja ole olemassa. Olioilla ei ole tyyppejä, joten koodia on kirjoitettava rajapintakoodiksi objekteille, joilla on tiettyjä ominaisuuksia ja metodeja. Moduulien väliset sopimukset perustuvat joukkoon metodeja ja ominaisuuksia, joiden oletetaan esiintyvän vaihdetuissa objekteissa.
Kapselointi on olennaista oliopohjaisessa ohjelmoinnissa. Se tarkoittaa, että tietyn objektin pitäisi pystyä kätkemään sisäisen toimintansa yksityiskohdat, jotta muut objektit, jotka ovat vuorovaikutuksessa sen kanssa, eivät ole riippuvaisia sen toteutuksen yksityiskohdista, vaan korkealla tasolla sovitusta rajapinnasta. Tämä tekee kehittäjien elämästä yksinkertaisempaa sekä palveluntarjoajan että käyttäjien puolella, koska molemmat tietävät, että toteutuksen yksityiskohdat voivat muuttua rikkomatta asiakasobjekteja.
Miksi tietojen paljastaminen rajapinnalla on huono ajatus
Javaskriptissä objekti on yksinkertaisesti sanakirja, joka koostuu ominaisuuksien nimistä, jotka on yhdistetty arvoihin, ja kun ominaisuuden arvo on funktio, kutsumme sitä metodiksi. Metodien välinen rajapinta on joukko ominaisuuksia, joita asiakaskoodi odottaa löytävänsä objektista.
Jos objekti paljastaa vain metodeja, rajapinta on helppo saada kehittymään ajan myötä. Metodi voi tarkistaa parametrit ja reagoida niiden mukaan. On myös mahdollista luoda uusia metodeja, jotka tarjoavat uusia ominaisuuksia. Ja tukea vanhoja, jotka sopeuttavat vanhan käyttäytymisen uuteen. Ominaisuuksien kanssa näin ei ole mahdollista tehdä.
Ominaisuuksien tapauksessa vakaan rajapinnan ylläpitäminen ei ole helppoa. Sillä oletusarvoisesti asiakaskoodi voi viitata objektin olemattomiin ominaisuuksiin. Kirjoittaminen olemattomaan ominaisuuteen luo sen. Sen lukeminen palauttaa määrittelemättömän. Asiakaskoodi ei pysty nopeasti havaitsemaan, jos se käyttää vanhentuneita ominaisuuksia. Mikä pahempaa, virhe voi levitä muihin koodin osiin, mikä vaikeuttaa ongelman havaitsemista.
Javaskriptin vakio-API:ssä on menetelmiä, joista voi olla hyötyä tällaisten ongelmien välttämisessä: on mahdollista jäädyttää tai sinetöidä objekti, jotta ei-tuettuja ominaisuuksien nimiä ei voi käyttää.
Getter/Setterit pelastavat tilanteen
Metodien toteutuksen yksityiskohtien piilottaminen on helppoa.
Getterit/setterit on otettu virallisesti käyttöön kielessä ECMAScript 5.1:ssä (ECMA-262). Niitä tuetaan tällä hetkellä kaikissa tärkeimmissä työpöytä- ja mobiiliselaimissa.
Perusidea on, että se lisää syntaksin, jolla accessor-ominaisuudet voidaan määritellä metodeiksi yksinkertaisten dataominaisuuksien sijaan. Getter määritellään avainsanalla get, jota seuraa ominaisuuden mukaan nimetty funktio, joka ei ota argumentteja ja palauttaa ominaisuuden arvon. Asettaja määritellään avainsanalla set, jota seuraa ominaisuuden mukaan nimetty funktio, joka ottaa parametrina ominaisuuden uuden arvon.
Oheinen esimerkki havainnollistaa getteriä ja setteriä, joita käytetään määriteltäessä accessor-ominaisuutta nimeltä prop:
var obj = { v: 0, get prop() { return this.v; }, set prop(newValue) { this.v = newValue; }};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);
Output:
042
Voidaan myös luoda vain lukuominaisuus määrittelemällä getteri ilman setteriä:
var obj = { get prop() { return -1; },};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);
Output:
-1-1
Ominaisuus voidaan tällöin korvata parilla metodilla, jotka luokan toteutuksen muuttuessa voivat reagoida siihen ja mukauttaa luokan käyttäytymistä. Pahimmassa tapauksessa se voi herättää poikkeuksen kertoakseen käyttäjälle, että ominaisuus on vanhentunut eikä sitä pitäisi enää käyttää.
Lisälukemista
Toivottavasti opit tässä postauksessa jotain uutta monimutkaisten evolutiivisten sovellusten suunnittelusta JavaScriptissä. Tässä osiossa annan sinulle pari linkkiä lisätietoa sisältäviin linkkeihin.
Tietoartikkelit
Tässä osiossa on pari lyhyttä artikkelia, jotka esittelevät käsitteitä ja antavat yleiskatsauksen aiheeseen liittyviin API:iin:
- Ominaisuuksien getterit ja setterit.
- JavaScript Getters and Setters
Edistyneempiä artikkeleita
Nämä artikkelit käsittelevät edistyneempiä aiheeseen liittyviä aiheita, kuten gettereiden ja settereiden tuomia ongelmia ja niiden ratkaisemista.
- Miksi getterit/setterit ovat huono idea JavaScriptissä
- Datan kapselointi JavaScriptissä
Viitedokumentaatio
Viimeiseksi, jotta voit todella hallita aihetta, linkit Mozillan dokumentaatioon aiheeseen liittyvistä API:ista:
- get ja set mahdollistavat gettereiden ja settereiden määrittelyn. Sen lisäksi, mitä selitimme tässä. On muitakin mielenkiintoisia ominaisuuksia, kuten tuki dynaamisesti luoduille ominaisuuksien nimille ja gettereiden ja settereiden käyttäminen simuloimaan arvojen asettamista/saamista arrayyn
- seal ja freeze mahdollistavat sen, että voidaan kontrolloida, mitkä objektin ominaisuudet ovat muokattavissa ja mitkä eivät ja miten. Sen avulla voidaan välttää se, että asiakkaat käyttävät objektin API:n vanhentuneita osia.
- defineProperty mahdollistaa gettereiden ja settereiden määrittelyn, ja samalla voidaan kontrolloida paremmin sitä, miten asiakkaat näkevät nämä ominaisuudet ja miten ne ovat muokattavissa.