Jack Franklin

December 23, 2013

Suurimmaksi osaksi JavaScriptissä näet sen, mitä saat. Arvo on arvo; ei ole mitään temppuja. Joskus kuitenkin halutaan arvo, joka perustuu joihinkin muihin arvoihin: esimerkiksi jonkun henkilön koko nimi on etu- ja sukunimen ketjutus. Jos sinulla on person-objekti ja haluat, että objektin käyttäjät voivat asettaa koko nimen, etunimen tai sukunimen ja nähdä muutoksen heijastuvan välittömästi muihin arvoihin, rakentaisit sen perinteisesti funktioiden avulla:

person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith

Mutta tämä on rumaa ja edellyttää, että objektin käyttäjät huolehtivat siitä, että ominaisuudet liittyvät toisiinsa; monimutkaisemmissa esimerkeissä tämä ei ehkä ole yhtä ilmeistä kuin nimien kanssa. Onneksi on olemassa parempi tapa, joka lisättiin ECMAScript 5:ssä.

Löydetään getterit ja setterit.

Miten

Tehdään tuo henkilöobjekti. Haluamme pystyä asettamaan etunimen, sukunimen tai koko nimen ja saada sen päivittämään kaksi muuta automaattisesti.

var person = { firstName: 'Jimmy', lastName: 'Smith', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName (name) { var words = name.toString().split(' '); this.firstName = words || ''; this.lastName = words || ''; }}

person.fullName = 'Jack Franklin';console.log(person.firstName); // Jackconsole.log(person.lastName) // Franklin

Mitä tässä tapahtuu?

Avainsanat get ja set ovat tärkeitä. Niiden jälkeen on ominaisuus, johon ne liittyvät (fullName) ja funktiorunko, joka määrittelee käyttäytymisen, kun ominaisuutta käytetään (name = person.fullName) tai muutetaan (person.fullName = 'Some Name').

Nämä kaksi avainsanaa määrittelevät accessor-funktiot: getter ja setter ominaisuudelle fullName. Kun ominaisuutta käytetään, käytetään getterin paluuarvoa. Kun arvo asetetaan, setteriä kutsutaan ja sille välitetään asetettu arvo. On sinusta kiinni, mitä teet tuolla arvolla, mutta se, mitä setteristä palautetaan, on arvo, joka välitettiin – sinun ei siis tarvitse palauttaa mitään.

Virallinen tapa: Object.defineProperty

Inline-menetelmän ohella gettereiden ja settereiden ilmoittaminen voidaan tehdä myös eksplisiittisemmin Object.defineProperty kautta (MDN Documentation). Tämä menetelmä ottaa kolme argumenttia. Ensimmäinen on objekti, johon ominaisuus lisätään, toinen on ominaisuuden nimi ja kolmas on objekti, joka kuvaa ominaisuutta (jota kutsutaan ominaisuuden kuvaajaksi). Tässä on esimerkki, joka toistaa yllä olevan esimerkin:

var person = { firstName: 'Jimmy', lastName: 'Smith'};

Object.defineProperty(person, 'fullName', {get: function() {return firstName + ' ' + lastName;},set: function(name) {var words = name.split(' ');this.firstName = words || '';this.lastName = words || '';}});

Eetu ei ole heti ilmeinen. Onko siitä muuta todellista hyötyä kuin se, että ominaisuuksia voidaan lisätä alkuperäisen objektin luomisen jälkeen?

Kun määrittelet ominaisuuden tällä tavalla, voit tehdä paljon muutakin kuin vain määritellä setterin tai getterin. Voit myös välittää seuraavat avaimet:

  • configurable (oletusarvoisesti false): jos tämä on tosi, ominaisuuden määritys on muokattavissa tulevaisuudessa.
  • enumerable (oletusarvoisesti false): jos tämä on tosi, ominaisuus ilmestyy näkyviin, kun objektin yli käydään silmukassa (for (var key in obj)).

Voidaan määritellä myös ominaisuuksia, joilla ei ole eksplisiittisiä gettereitä tai settereitä:

Object.defineProperty(person, 'age', { value: 42});

Tämä luo person.age ja asettaa sen arvoksi 42. On tärkeää huomata, että tämä ominaisuus ei ole kirjoitettavissa. Kutsumalla person.age = 99 ei ole vaikutusta. Tällä tavalla voit luoda vain lukukäyttöön tarkoitettuja ominaisuuksia. Jos ominaisuudelle on asetettu value-avain, sillä ei voi olla getteriä tai setteriä. Ominaisuuksilla voi olla arvoja tai accessoreita, ei molempia.

Ei vain sitä, vaan koska enumerable-ominaisuuden oletusarvo on false, tämä ominaisuus ei näy, kun käymme silmukassa läpi objektin avaimia.

Jos haluaisimme tehdä ominaisuuden kirjoitettavaksi, meidän täytyisi asettaa writable-ominaisuus:

Object.defineProperty(person, 'age', { value: 42, writable: true});

Nyt person.age = 99; saa aikaan halutun vaikutuksen.

Ylikäyttö

Muista: vain koska ominaisuus on olemassa, sitä ei tarvitse käyttää koko ajan. Gettereillä ja settereillä on käyttötapauksensa, mutta älä liioittele, tai päädyt todennäköisesti suunnitteluun, joka on hämmentävä niiden kannalta, jotka ovat vuorovaikutuksessa objekteidesi kanssa. Huolellisesti käytettynä ne ovat erittäin tehokkaita. Mutta suuren vallan myötä tulee myös suuri vastuu.

Tuki selaimille?

IE9:ssä ja uudemmissa versioissa on täysi tuki Object.defineProperty:lle, samoin kuin Safari 5+, Firefox 4+, Chrome 5+ ja Opera 12+. Jos käytät Node.js:ää, tuki on täysi. Etkö vain rakasta Nodea?!”

Tämä artikkeli on kirjoitettu yhdessä Tom Ashworthin kanssa. Kiitos Tomille kaikesta hänen avustaan tämän kokoamisessa.

Jos pidit tästä kirjoituksesta, liity uutiskirjeeseen saadaksesi päivityksiä uudesta sisällöstä 😎.

Kaikki blogikirjoitukset

Jos pidit tästä kirjoituksesta, muista seurata minua Twitterissä.

Vastaa

Sähköpostiosoitettasi ei julkaista.