Getters en setters zijn functies of methoden die worden gebruikt om de waarden van variabelen te krijgen en in te stellen. Het getter-setter-concept is gebruikelijk in computerprogrammering: bijna alle programmeertalen op hoog niveau hebben een set syntaxis om getters en setters te implementeren, inclusief JavaScipt.
Lees ook: 4 Nuttige JavaScript Statements die je moet kennen
In deze post zullen we zien wat getters setters zijn, en hoe je ze kunt maken en gebruiken in JavaScript.
- Getters-setters en inkapseling
- Getters en setters maken
- 1. Met methoden
- 2. Met trefwoorden
- Welke manier is beter?
- Overschrijving preventie
- Operaties binnen getters en setters
- Bescherm gegevens met getters en setters
- Onbeschermde gegevens
- 1. Block scoping
- 2. Function scoping
- 3. Gegevensbescherming zonder scoping
- Wanneer moet je getters en setters gebruiken?
Getters-setters en inkapseling
Het idee van getters en setters wordt altijd genoemd in combinatie met inkapseling. Inkapseling kan op twee manieren worden opgevat.
In de eerste plaats is het het instellen van de data-getters-setters trio om die data te benaderen en te wijzigen. Deze definitie is nuttig wanneer sommige operaties, zoals validatie, moeten worden uitgevoerd op de gegevens voordat ze worden opgeslagen of bekeken-getters en setters bieden de perfecte thuisbasis voor het.
Tweede, er is een strengere definitie volgens welke inkapseling wordt gedaan om gegevens te verbergen, om het ontoegankelijk te maken voor andere code, behalve via de getters en setters. Op deze manier kunnen we niet per ongeluk belangrijke gegevens overschrijven met andere code in het programma.
Getters en setters maken
1. Met methoden
Omdat getters en setters in feite functies zijn die een waarde ophalen/wijzigen, zijn er meer dan één manieren om ze te maken en te gebruiken. De eerste manier is:
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"
Dit is de eenvoudigste manier om getters en setters te maken. Er is een eigenschap foo
en er zijn twee methoden: getFoo
en setFoo
om een waarde terug te geven en toe te wijzen aan die eigenschap.
2. Met trefwoorden
Een meer “officiële” en robuuste manier om getters en setters te maken is door gebruik te maken van de get
en set
trefwoorden.
Om een getter te maken, plaatst u het get
trefwoord voor een functiedeclaratie die zal dienen als de getter methode, en gebruikt u het set
trefwoord op dezelfde manier om een setter te maken. De syntaxis is als volgt:
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"
Merk op dat de gegevens alleen kunnen worden opgeslagen onder een property-naam (fooVal
) die verschilt van de naam van de getter-setter methoden (foo
), omdat een property die de getter-setter bevat, niet ook de gegevens kan bevatten.
Welke manier is beter?
Als je ervoor kiest om getters en setters met trefwoorden te maken, kun je de toewijzingsoperator gebruiken om de gegevens in te stellen en de puntoperator om de gegevens op te halen, op dezelfde manier als je de waarde van een gewone eigenschap zou openen/instellen.
Als je echter kiest voor de eerste manier van coderen van getters en setters, moet je de setter en getter methoden aanroepen met de functie-aanroep syntaxis, omdat het typische functies zijn (niets speciaals als die gemaakt met de get
en set
trefwoorden).
Ook is er een kans dat je per ongeluk een andere waarde toewijst aan de eigenschappen die deze getter-setter methoden bevatten en ze volledig verliest! Iets waar je je in de latere methode geen zorgen over hoeft te maken.
Dus, je kunt zien waarom ik zei dat de tweede techniek robuuster is.
Overschrijving preventie
Als je om een of andere reden de voorkeur geeft aan de eerste techniek, maak dan de eigenschappen die de getter-setter methoden bevatten alleen-lezen door ze te maken met Object.defineProperties
. Met Object.defineProperties
, Object.defineProperty
en Reflect.defineProperty
aangemaakte eigenschappen worden automatisch geconfigureerd naar writable: false
, wat betekent: alleen-lezen:
/* 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"
Operaties binnen getters en setters
Als je eenmaal de getters en setters hebt ingevoerd, kun je doorgaan en operaties op de gegevens uitvoeren voordat je ze wijzigt of terugstuurt.
In de code hieronder worden in de getter-functie de gegevens samengevoegd met een string voordat ze worden geretourneerd, en in de setter-functie wordt een validatie uitgevoerd of de waarde een getal is of niet voordat n
wordt bijgewerkt.
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"
Bescherm gegevens met getters en setters
Zo ver hebben we het gebruik van getters en setters in de eerste context van inkapseling behandeld. Laten we overgaan tot de tweede, d.w.z. hoe je gegevens kunt verbergen voor code van buitenaf met behulp van getters en setters.
Onbeschermde gegevens
Het instellen van getters en setters betekent niet dat de gegevens alleen via die methoden kunnen worden benaderd en gewijzigd. In het volgende voorbeeld wordt de data direct veranderd zonder de getter en setter methodes aan te raken:
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"
We hebben de setter niet gebruikt maar de data direct veranderd (fooVal
). De gegevens die we aanvankelijk in obj
hadden gezet zijn nu weg! Om te voorkomen dat dit (per ongeluk) gebeurt, moet je je gegevens beschermen. Je kunt dat doen door het bereik te beperken van waar je data beschikbaar is. Je kunt dat doen door ofwel block scoping ofwel function scoping.
1. Block scoping
Eén manier is het gebruik van een block scope waarbinnen de gegevens worden gedefinieerd met behulp van het let
keyword dat de scope beperkt tot dat blok.
Een block scope kan worden gemaakt door uw code binnen een paar accolades te plaatsen. Wanneer u een block scope maakt, laat er dan een commentaar boven staan met de vraag om de accolades met rust te laten, zodat niemand per ongeluk de accolades verwijdert en denkt dat het extra overbodige accolades in de code zijn of een label toevoegt aan de block scope.
/* 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"
Het veranderen/creëren van fooVal
buiten het blok heeft geen invloed op de fooVal
waarnaar verwezen wordt in de getters setters.
2. Function scoping
De meer gebruikelijke manier om de gegevens te beschermen met scoping is door de gegevens binnen een functie te houden en een object terug te sturen met de getters en setters van die functie.
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"
Het object (met de foo()
getter-setter erin) dat door de myobj()
functie wordt geretourneerd, wordt opgeslagen in obj
, en dan wordt obj
gebruikt om de getter en setter aan te roepen.
3. Gegevensbescherming zonder scoping
Er is ook een andere manier waarop u uw gegevens kunt beschermen tegen overschrijven zonder de reikwijdte ervan te beperken. De logica hierachter is als volgt: hoe kun je een stuk gegevens veranderen als je niet weet hoe het heet?
Als de gegevens een niet zo gemakkelijk reproduceerbare variabele/eigenschapsnaam hebben, is de kans groot dat niemand (zelfs wijzelf niet) het uiteindelijk zal overschrijven door een waarde toe te kennen aan die variabele/eigenschapsnaam.
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"
Zie, dat is één manier om dingen uit te werken. Hoewel de naam die ik koos niet echt goed is, kun je ook willekeurige waarden of symbolen gebruiken om eigenschapsnamen te maken, zoals voorgesteld door Derick Bailey in deze blog post. Het belangrijkste doel is om de gegevens verborgen te houden voor andere code en een getter-setter paar te laten openen/bijwerken.
Wanneer moet je getters en setters gebruiken?
Nu komt de grote vraag: begin je nu met het toewijzen van getters en setters aan al je gegevens?
Als je gegevens verbergt, dan is er geen andere keus.
Maar als je gegevens die door andere code gezien worden prima zijn, moet je dan nog steeds getters setters gebruiken, alleen maar om ze te bundelen met code die er enkele bewerkingen op uitvoert? Ik zou zeggen van wel. Code telt snel op. Het maken van micro eenheden van individuele data met zijn eigen getter-setter geeft je een zekere onafhankelijkheid om aan die data te werken zonder andere delen van de code te beïnvloeden.
Lees ook: 10 Redenen waarom je code optimalisatie nodig hebt