Jack Franklin

December 23, 2013

Voor het grootste deel, in JavaScript, is wat je ziet wat je krijgt. Een waarde is een waarde; er zijn geen trucs. Soms wil je echter een waarde die gebaseerd is op een aantal andere waarden: iemands volledige naam is bijvoorbeeld een aaneenschakeling van voor- en achternaam. Als je een person object hebt, en je wilt dat de gebruikers van dat object de volledige, voor- of achternaam kunnen instellen, en die verandering onmiddellijk terugzien in de andere waarden, dan zou je het conventioneel bouwen met functies:

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

Maar dit is lelijk, en vereist dat de gebruikers van je object zich ervan bewust zijn dat de eigenschappen aan elkaar gerelateerd zijn; in een complexer voorbeeld is dat misschien niet zo duidelijk als bij namen. Gelukkig is er een betere manier, toegevoegd in ECMAScript 5.

Met getters en setters.

Hoe

Laten we dat persoonsobject maken. We willen de voornaam, achternaam of volledige naam kunnen instellen, en de andere twee automatisch laten bijwerken.

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

Dus wat gebeurt hier?

De get en set keywords zijn belangrijk. Na hen is de eigenschap waarop zij betrekking hebben (fullName) en een functie lichaam dat het gedrag bepaalt wanneer de eigenschap wordt benaderd (name = person.fullName) of gewijzigd (person.fullName = 'Some Name').

Deze twee sleutelwoorden definiëren accessor functies: een getter en een setter voor de fullName eigenschap. Wanneer de eigenschap wordt benaderd, wordt de retourwaarde van de getter gebruikt. Wanneer een waarde wordt ingesteld, wordt de setter aangeroepen en wordt de ingestelde waarde doorgegeven. Het is aan jou wat je met die waarde doet, maar wat wordt teruggegeven van de setter is de waarde die werd doorgegeven – dus je hoeft niets terug te geven.

De officiële manier: Object.defineProperty

Naast de inline methode om getters en setters te declareren, kan het ook explicieter via Object.defineProperty (MDN Documentatie). Deze methode neemt drie argumenten. Het eerste is het object waaraan de eigenschap moet worden toegevoegd, het tweede is de naam van de eigenschap, en het derde is een object dat de eigenschap beschrijft (bekend als de descriptor van de eigenschap). Hier is een voorbeeld dat het bovenstaande voorbeeld repliceert:

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 || '';}});

Het voordeel hier is niet onmiddellijk duidelijk. Is er, behalve de mogelijkheid om eigenschappen toe te voegen na het maken van het initiële object, een echt voordeel?

Wanneer je een eigenschap op deze manier definieert, kun je veel meer doen dan alleen een setter of getter definiëren. U kunt ook de volgende sleutels doorgeven:

  • configurable (false standaard): als dit waar is, zal de configuratie van de eigenschap in de toekomst kunnen worden gewijzigd.
  • enumerable (false standaard): als dit waar is, zal de eigenschap verschijnen bij het lussen over het object (for (var key in obj)).

We kunnen ook eigenschappen definiëren die geen expliciete getters of setters hebben:

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

Dit zal person.age creëren, en het instellen op de waarde 42. Het is belangrijk op te merken dat deze eigenschap niet beschrijfbaar is. Het aanroepen van person.age = 99 zal geen effect hebben. Op deze manier kunt u alleen-lezen eigenschappen maken. Als een eigenschap een value sleutel heeft, kan het geen getter of setter hebben. Eigenschappen kunnen waarden of accessors hebben, niet beide.

Niet alleen dat, maar omdat de enumerable eigenschap standaard op false staat, zal deze eigenschap niet verschijnen wanneer we over de sleutels van het object lussen.

Als we een eigenschap beschrijfbaar willen maken, zouden we de writable eigenschap moeten instellen:

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

Nu zal person.age = 99; het gewenste effect hebben.

Overmatig gebruik

Houd in gedachten: alleen omdat een eigenschap bestaat, hoeft die niet altijd gebruikt te worden. Getters en Setters hebben hun nut, maar ga niet te ver, of je zult hoogstwaarschijnlijk eindigen met een ontwerp dat verwarrend is voor degenen die met je objecten werken. Als je ze voorzichtig gebruikt, zijn ze zeer krachtig. Maar met grote kracht komt grote verantwoordelijkheid.

Browser ondersteuning?

IE9 en hoger hebben volledige ondersteuning voor Object.defineProperty, samen met Safari 5+, Firefox 4+, Chrome 5+ en Opera 12+. Als je met Node.js werkt, is er volledige ondersteuning. Hou je niet gewoon van Node?!

Dit artikel is geschreven in samenwerking met Tom Ashworth. Met dank aan Tom voor al zijn hulp bij het samenstellen van dit artikel.

Als u dit artikel interessant vond, schrijf u dan in voor de nieuwsbrief om op de hoogte te blijven van nieuwe inhoud 😎.

Alle blogberichten

Als u dit artikel interessant vond, volg me dan op Twitter.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.