Hankkijat ja asettajat ovat funktioita tai metodeja, joita käytetään muuttujien arvojen hankkimiseen ja asettamiseen. Getter-setter-käsite on yleinen tietokoneohjelmoinnissa: lähes kaikissa korkean tason ohjelmointikielissä on joukko syntaksia gettereiden ja settereiden toteuttamiseksi, myös JavaSciptissä.
Lue myös: 4 Hyödyllistä JavaScript-lausetta, jotka sinun tulisi tuntea
Tässä postauksessa katsotaan, mitä getterit-setterit ovat ja miten niitä luodaan ja käytetään JavaScriptissä.
- Getterit-setterit ja kapselointi
- Luo getterit ja setterit
- 1. Metodeilla
- 2. Avainsanoilla
- Kumpi tapa on parempi?
- Oversrite prevention
- Operaatiot gettereiden ja settereiden sisällä
- Datan suojaaminen gettereiden ja settereiden avulla
- Suojaamaton data
- 1. Lohkon rajaus
- 2. Funktion rajaus
- 3. Tiedon suojaaminen ilman scopingia
- Milloin kannattaa käyttää gettereitä ja settereitä?
Getterit-setterit ja kapselointi
Getterien ja settereiden idea mainitaan aina kapseloinnin yhteydessä. Kapselointi voidaan ymmärtää kahdella tavalla.
Ensiksikin se on datan asettaminen – getters-setters-kolmikko, jolla tuota dataa voidaan käyttää ja muokata. Tämä määritelmä on hyödyllinen silloin, kun tiedolle on suoritettava joitakin operaatioita, kuten validointi, ennen sen tallentamista tai katsomista – getterit ja setterit tarjoavat siihen täydellisen kodin.
Toisekseen on olemassa tiukempi määritelmä, jonka mukaan kapselointi tehdään datan piilottamiseksi, jotta se olisi saavuttamattomissa muusta koodista, paitsi gettereiden ja settereiden kautta. Näin emme päädy vahingossa kirjoittamaan tärkeää dataa päälle jollain muulla ohjelmassa olevalla koodilla.
Luo getterit ja setterit
1. Metodeilla
Koska getterit ja setterit ovat periaatteessa funktioita, jotka hakevat/muuttavat arvoa, on olemassa useampia tapoja luoda ja käyttää niitä. Ensimmäinen tapa on:
var obj = { foo: 'this is the value of foo', getFoo: function() { return this.foo; }, setFoo: function(val) { this.foo = val; }}console.log(obj.getFoo());// "this is the value of foo"obj.setFoo('hello');console.log(obj.getFoo());// "hello"
Tämä on yksinkertaisin tapa luoda gettereitä ja settereitä. On ominaisuus foo
ja on kaksi metodia: getFoo
ja setFoo
, joilla palautetaan ja annetaan arvo kyseiselle ominaisuudelle.
2. Avainsanoilla
”Virallisempi” ja vankempi tapa luoda gettereitä ja settereitä on käyttää avainsanoja get
ja set
.
Luoaksesi getterin aseta avainsana get
sen funktio-julistuksen eteen, joka toimii getterin metodina.
Luoaksesi getterin asetetaan avainsana set
samalla tavalla. Syntaksi on seuraava:
var obj = { fooVal: 'this is the value of foo', get foo() { return this.fooVal; }, set foo(val) { this.fooVal = val; }}console.log(obj.foo);// "this is the value of foo"obj.foo = 'hello';console.log(obj.foo);// "hello"
Huomaa, että tiedot voidaan tallentaa vain ominaisuuden nimellä (fooVal
), joka on eri kuin getter-setter-metodien nimi (foo
), koska getter-setterin sisältävä ominaisuus ei voi pitää sisällään myös tietoja.
Kumpi tapa on parempi?
Jos päätät luoda getterit ja setterit avainsanoilla, voit käyttää assignment-operaattoria tietojen asettamiseen ja piste-operaattoria tietojen hakemiseen samalla tavalla kuin tavallisen ominaisuuden arvoa käytettäisiin/asetettaisiin.
Jos kuitenkin valitset ensimmäisen tavan koodata getterit ja setterit, sinun on kutsuttava setteri- ja getter-metodeja funktiokutsusyntaksilla, koska ne ovat tyypillisiä funktioita (ei mitään erikoista, kuten avainsanoilla get
ja set
luodut funktiot).
Lisäksi on mahdollista, että päädyt vahingossa osoittamaan jonkun muun arvon ominaisuuksille, jotka pitivät sisällään nämä getter-setter-metodit, ja menetät ne kokonaan! Jotain, mistä sinun ei tarvitse huolehtia myöhemmässä menetelmässä.
Voit siis ymmärtää, miksi sanoin, että toinen tekniikka on kestävämpi.
Oversrite prevention
Jos jostain syystä pidät enemmän ensimmäisestä tekniikasta, tee getter-setter-metodien hallussaan pitämistä ominaisuuksista luku-oikeutettuja luomalla ne käyttämällä Object.defineProperties
. Object.defineProperties
:n, Object.defineProperty
:n ja Reflect.defineProperty
:n avulla luodut ominaisuudet konfiguroituvat automaattisesti writable: false
:ksi, mikä tarkoittaa lukukieltoa:
/* Overwrite prevention */var obj = { foo: 'this is the value of foo'};Object.defineProperties(obj, { 'getFoo': { value: function () { return this.foo; } }, 'setFoo': { value: function (val) { this.foo = val; } }});obj.getFoo = 66;// getFoo is not going to be overwritten!console.log(obj.getFoo());// "this is the value of foo"
Operaatiot gettereiden ja settereiden sisällä
Kun olet ottanut käyttöön getterit ja setterit, voit edetä ja suorittaa operaatioita tiedoille, ennen kuin muutat tai palautat ne.
Oheisessa koodissa getter-funktiossa data ketjutetaan merkkijonon kanssa ennen palauttamista, ja setter-funktiossa suoritetaan ennen n
:n päivittämistä validointi siitä, onko arvo luku vai ei.
var obj = { n: 67, get id() { return 'The ID is: ' + this.n; }, set id(val) { if (typeof val === 'number') this.n = val; }}console.log(obj.id);// "The ID is: 67"obj.id = 893;console.log(obj.id);// "The ID is: 893"obj.id = 'hello';console.log(obj.id);// "The ID is: 893"
Datan suojaaminen gettereiden ja settereiden avulla
Siinä asti käsiteltiin gettereiden ja settereiden käyttöä kapseloinnin ensimmäisessä yhteydessä. Siirrytäänpä toiseen eli siihen, miten data voidaan piilottaa ulkopuoliselta koodilta gettereiden ja settereiden avulla.
Suojaamaton data
Getterien ja settereiden asettaminen ei tarkoita, että dataa voi käyttää ja muuttaa vain näiden metodien kautta. Seuraavassa esimerkissä sitä muutetaan suoraan koskematta getter- ja setter-metodeihin:
var obj = { fooVal: 'this is the value of foo', get foo() { return this.fooVal; }, set foo(val) { this.fooVal = val; }}obj.fooVal = 'hello';console.log(obj.foo);// "hello"
Me emme käyttäneet setteriä vaan muutimme dataa suoraan (fooVal
). Data, jonka alun perin asetimme obj
:n sisälle, on nyt poissa! Jotta tällaista ei tapahtuisi (vahingossa), tarvitset jonkinlaista suojausta tiedoillesi. Voit lisätä sen rajoittamalla sen alueen, jossa datasi on käytettävissä. Voit tehdä sen joko lohkojen tai funktioiden rajauksella.
1. Lohkon rajaus
Yksi tapa on käyttää lohkon laajuutta, jonka sisällä data määritellään käyttämällä let
-avainsanaa, joka rajoittaa sen laajuuden kyseiseen lohkoon.
Lohkon laajuus voidaan luoda sijoittamalla koodisi aaltosulkeiden sisään. Aina kun luot lohkon laajuuden, muista jättää sen yläpuolelle kommentti, jossa pyydät jättämään hakasulkeet rauhaan, jotta kukaan ei vahingossa poista hakasulkeita luullen niitä ylimääräisiksi turhiksi hakasulkeiksi koodissa tai lisää lohkon laajuuteen merkintää.
/* BLOCK SCOPE, leave the braces alone! */{let fooVal = 'this is the value of foo';var obj = { get foo() { return fooVal; }, set foo(val) { fooVal = val } }}fooVal = 'hello';// not going to affect the fooVal inside the blockconsole.log(obj.foo);// "this is the value of foo"
Lohkon ulkopuolella olevien fooVal
muuttaminen/luominen ei vaikuta fooVal
:n sisäpuolelle viitattuihin fooVal
:iin, jotka ovat gettersettereissä settereissä.
2. Funktion rajaus
Yleisempi tapa suojata tiedot rajauksen avulla on pitää tiedot funktion sisällä ja palauttaa funktiosta objekti, jossa on kyseisen funktion getterit ja setterit.
function myobj(){ var fooVal = 'this is the value of foo'; return { get foo() { return fooVal; }, set foo(val) { fooVal = val } }}fooVal = 'hello';// not going to affect our original fooValvar obj = myobj();console.log(obj.foo);// "this is the value of foo"
Funktion myobj()
palauttama objekti (jonka sisällä on foo()
getteri-setteri foo()
) tallennetaan obj
:een, ja sitten obj
:aa käytetään kutsuttaessa getteriä ja setteriä.
3. Tiedon suojaaminen ilman scopingia
On myös toinen tapa suojata data ylikirjoittamiselta rajoittamatta sen scopea. Logiikka sen takana menee näin: Miten voit muuttaa dataa, jos et tiedä, mitä sen nimi on?
Jos datalla on vaikeasti toistettava muuttujan/ominaisuuden nimi, on todennäköistä, ettei kukaan (edes me itse) päädy ylikirjoittamaan sitä antamalla kyseiselle muuttujalle/ominaisuuden nimelle jonkin arvon.
var obj = { s89274934764: 'this is the value of foo', get foo() { return this.s89274934764; }, set foo(val) { this.s89274934764 = val; }}console.log(obj.foo);// "this is the value of foo"
Tämä on yksi keino, jolla asiat voidaan hoitaa. Vaikka valitsemani nimi ei olekaan kovin hyvä, voit myös käyttää satunnaisia arvoja tai symboleja ominaisuuksien nimien luomiseen, kuten Derick Bailey ehdottaa tässä blogikirjoituksessa. Päätavoitteena on pitää data piilossa muulta koodilta ja antaa getter-setter-parin päästä siihen käsiksi/päivittää sitä.
Milloin kannattaa käyttää gettereitä ja settereitä?
Nyt tulee iso kysymys: alatko nyt määrätä gettereitä ja settereitä kaikkeen dataan?
Jos piilotat dataa, muuta vaihtoehtoa ei ole.
Mutta jos datasi näkyminen muulle koodille on kunnossa, tarvitseeko sinun silti käyttää gettereitä ja settereitä vain niputtaaksesi sen koodin kanssa, joka suorittaa joitakin operaatioita sillä? Sanoisin että kyllä. Koodia kertyy hyvin nopeasti. Yksittäisen datan mikroyksiköiden luominen omilla getter-settereillään antaa sinulle tietynlaisen riippumattomuuden työskennellä kyseisen datan parissa vaikuttamatta koodin muihin osiin.
Lue myös: 10 syytä, miksi tarvitset koodin optimointia