Begrebet getters og setters er ret almindeligt blandt de populære sprog, der anvendes i dag. Har du nogensinde haft brug for at sikre, at en given handling altid udføres før eller efter tildeling af en værdi til en objektets egenskab? Dette er muligt med setters. Du kan også udføre enhver form for behandling, når du henter værdien af en egenskab ved hjælp af getters (f.eks. formatering). En måde at implementere getters og setters på er at bruge metoder, ligesom det er tilfældet i Java. Siden ES5 har vi imidlertid fået et meget mere elegant og praktisk alternativ til rådighed ved at bruge get
– og set
-syntaksen. Nå, lad os komme i gang!
I JavaScript er objekter samlinger af egenskaber, og du har sikkert brugt dem til at gemme data før. En egenskab er simpelthen et nøgle-værdipar. Her er et eksempel:
const options = {
timeout: 5000,
retries: 3,
ip: '192.168.1.20',
port: 4001,
};
Properties i et objekt kan nemt indstilles og aflæses, som her:
artist.name = 'Carice Anouk van Houten';console.log(artist.name); //=> "Carice Anouk van Houten"
Og det er bestemt ikke noget nyt, hvis du allerede har haft en vis erfaring med JavaScript. For at skelne mellem disse almindelige egenskaber og den anden type, som vi vil se i denne artikel, kan vi kalde førstnævnte for “dataegenskaber”.
Getters og setters: den gamle måde
For ES5 var den eneste måde, vi kunne implementere getters og setters på, at bruge almindelige metoder. Som i eksemplet nedenfor:
Jeg har beholdt nøgleordet funktion i ovenstående eksempel for at gøre det klart, at der ikke er nogen magi her. Kun normale metoder. Vi kunne have opnået den samme effekt ved at bruge ES2015’s metodedefinitionssyntaks, som er kortere og noget mere elegant:
const config = {
_port: 4001,
setPort(port) {
// ...
},
getPort() {
// ...
},
};
Brugen af disse typer getters og setters er ret enkel:
config.setPort(8080);
console.log(config.getPort()); //=> 8080
Inkrementering af en værdi ville blive gjort på denne måde:
item.setQuantity(item.getQuantity() + 1);
Det ser virkelig langtrukkent ud, når man sammenligner med at inkremere en egenskab direkte:
item.quantity += 1;
// Or even simpler...
item.quantity++;
Getters og setters: hvorfor?
I OO-sprog som Java, C++ eller C# er det muligt at eksponere en klasses medlemmer på forskellige niveauer ved hjælp af adgangsmodifikatorer (som f.eks. public
, protected
og private
). Dette tjener til at implementere et vigtigt koncept i OOP kaldet datahiding.
En meget almindelig anvendelse af getters og setters i disse sprog er at eksponere medlemmer af en klasse på en sikker måde. Du kan f.eks. kun implementere en getter for at sikre, at et privat medlem aldrig vil blive ændret udefra i klassen. En setter kan til gengæld bruges til at validere de leverede værdier og bevare integriteten af instanser af den pågældende klasse.
Hvad med JavaScript?
I JavaScript er tingene en smule anderledes. På det tidspunkt, hvor denne artikel er skrevet, findes der ingen access modifiers i JS. I øjeblikket er den bedste mulighed, vi har, at bruge symboler, som giver os en vis grad af fortrolighed, når de bruges som nøgler. Nogle mennesker bryder sig dog ikke om dem. Især fordi det er let at bryde dette privatliv ved at bruge reflection.
Jeg anser ikke dette for at være et reelt problem, da sprog, der har reflection, normalt giver programmører mulighed for at bryde indkapslingen på en eller anden måde. Det problem jeg ser i symboler er, at de ikke er så praktiske at bruge som en simpel privat accessor ville være. Den gode nyhed er, at et EcmaScript-forslag, der omfatter private felter, allerede er i fase 3. Og de vil være immune over for enhver form for refleksion.
I eksemplet i det foregående afsnit brugte vi ikke symboler eller andre tricks til at simulere et privat medlem. _port
-egenskaben har ikke noget særligt i sig selv. Det er bare en almindelig dataegenskab, og som sådan kan den indstilles eller læses direkte, helt uden om den getter og setter, som vi har oprettet.
Da det ikke er formålet med denne artikel at forklare symboler og andre indkapslingsteknikker, implementerer jeg ikke private egenskaber i dens kodeeksempler. Du skal blot huske på, at getters og setters almindeligvis (men ikke altid) bruges til at give adgang til indkapslede medlemmer. Endelig skal du bemærke den understregning, der går forud for navnet på _port
-egenskaben. Det er en de facto-konvention blandt JS-udviklere, der angiver, at en given egenskab er privat og ikke bør tilgås udefra i den klasse, hvor den er defineret.
Getters og setters: den nye måde med accessor-properties
Accessor-properties er den moderne måde at definere getters og setters på. Når det kommer til deres definition, er de ikke så forskellige fra vores tidligere eksempel, men det er deres anvendelse, der er virkelig anderledes. Lad os først tilpasse vores kode til at bruge accessor properties:
Som du kan se, er der kun to ting, der er ændret i dette eksempel:
- I stedet for at have
setPort
oggetPort
metoder. Vi brugerset
– ogget
-syntaksen sammen med et enkelt navn til egenskaben (“port
” i dette eksempel) - Vi har ikke brug for nøgleordet
function
her. Faktisk får du en SyntaxError, hvis du forsøger at bruge det.
Hvordan bruger man accessor-egenskaber?
Hvis definitionen af en accessor-egenskab er ganske lig den måde, vi opretter gammeldags getters og setters på, har deres brug ingen synlig forskel fra den måde, vi bruger almindelige dataegenskaber:
config.port = 8080;
console.log(config.port); //=> 8080
Og sådan her ser et inkrementeringsudtryk ud:
timer.seconds += 1;
Ja. Så enkelt er det. =)
Konklusion
- Objekter er samlinger af egenskaber
- En almindelig egenskab er blot et nøgle-værdipar og kan kaldes en “dataegenskab”
- Du kan implementere getters og setters som normale metoder. Det er den “gammeldags” måde at gøre det på i JavaScript.
- Getters og setters bruges normalt til at give adgang til private medlemmer af en klasse.
- Accessor properties kan opføre sig præcis som gammeldags-metode-baserede getters og setters, men deres brug er designet til at få dem til at ligne dataegenskaber.
Vil du beherske JavaScript? Jeg kan varmt anbefale Mosh’s JavaScript-kurser.
Og hvis du kunne lide denne artikel, så del den også med andre!