Datakapsling i JavaScript: getters och setters

Datakapsling i JavaScript: getters och setters

När man bygger större JavaScript-applikationer behöver man snart dela upp dem i moduler som är kopplade till varandra genom tydliga kontrakt. När det gäller långsiktigt underhåll måste det finnas ett sätt att bibehålla kompatibilitet vid gränssnittsändringar. För att göra det förlitar sig objektorienterade språk på inkapsling eller information som döljer implementeringsdetaljer från användarna av en kodbit, så att den kan ändras utan att klienterna påverkas.

I det här inlägget kommer vi att prata om datainkapsling i JavaScript. Mer specifikt kommer vi att prata om inkapsling av egenskaper bakom getters och setters.

Några begrepp

JavaScript utformades med principen om duck typing som grund:

“När jag ser en fågel som går som en anka, simmar som en anka och kvackar som en anka kallar jag den fågeln för en anka.”

Med andra ord är JavaScript i grunden ett objektorienterat språk, men till skillnad från andra objektorienterade språk som C# och Java är klasser i JavaScript andra klassens medborgare och gränssnitt existerar inte. Objekt har inga typer och därför måste kod skrivas för att skapa gränssnitt mot objekt som har vissa egenskaper och metoder. Kontrakt mellan moduler baseras på en uppsättning metoder och egenskaper som antas finnas i de utbytta objekten.

Inkapsling är grundläggande i objektorienterad programmering. Det innebär att ett givet objekt bör kunna dölja detaljerna i sitt inre arbete, så att andra objekt som interagerar med det inte är beroende av detaljerna i dess implementering, utan av ett överenskommet gränssnitt på hög nivå. Detta gör livet enklare för utvecklare, både på leverantörens och användarnas sida, eftersom båda vet att implementeringsdetaljerna kan ändras utan att klientobjekten går sönder.

Varför det är en dålig idé att exponera data i ett gränssnitt

I JavaScript är ett objekt helt enkelt ett lexikon med egenskapsnamn som mappas till värden, när värdet på en egenskap är en funktion kallar vi det för en metod. Gränssnittet mellan metoder är den uppsättning egenskaper som klientkoden förväntar sig att hitta på ett objekt.

Om ett objekt endast exponerar metoder är det lätt att få gränssnittet att utvecklas med tiden. En metod kan kontrollera sina parametrar och reagera därefter. Det är också möjligt att skapa nya metoder som tillhandahåller nya funktioner. Och stödja gamla metoder som anpassar det gamla beteendet till det nya. Med egenskaper är det inte möjligt att göra det.

Inför egenskaper är det inte lätt att hålla ett stabilt gränssnitt. För som standard kan klientkoden hänvisa till icke-existerande egenskaper hos ett objekt. Att skriva till en icke-existerande egenskap kommer att skapa den. När du läser den returnerar du odefinierat. Klientkoden kan inte snabbt upptäcka om den använder föråldrade egenskaper. Vad värre är, felet kan spridas till andra delar av koden, vilket gör det svårare att upptäcka problemet.

Standard-API:et för JavaScript har metoder som kan vara användbara för att undvika sådana problem: Det är möjligt att frysa eller försegla ett objekt, så att ej stödda egenskapsnamn inte kan användas.

Getter/Setters för att rädda dagen

Det är lätt att dölja detaljerna i metodimplementationen.

Getters/setters har officiellt införts i språket i ECMAScript 5.1 (ECMA-262). De stöds för närvarande i alla större webbläsare för datorer och mobiler.

Den grundläggande idén är att man lägger till syntax för att definiera accessoregenskaper som metoder, i stället för enkla dataegenskaper. En getter definieras med nyckelordet get följt av en funktion som namnges efter egenskapen, som inte tar några argument och returnerar värdet på egenskapen. En setter definieras med nyckelordet set följt av en funktion som namnges efter egenskapen och som tar egenskapens nya värde som parameter.

Följande exempel illustrerar en getter och en setter som används för att definiera en accessor-egenskap som heter prop:

var obj = { v: 0, get prop() { return this.v; }, set prop(newValue) { this.v = newValue; }};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);

Output:

042

Det går också att skapa en skrivskyddad egenskap genom att definiera en getter utan setter:

var obj = { get prop() { return -1; },};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);

Output:

-1-1

En egenskap kan sedan ersättas av ett par metoder som, om implementationen av en klass ändras, kan reagera på detta och anpassa klassens beteende. I värsta fall kan den ta upp ett undantag för att tala om för användaren att egenskapen är föråldrad och inte bör användas längre.

Fortsatt läsning

Jag hoppas att du har lärt dig något nytt om att utforma komplexa evolutiva applikationer i JavaScript i det här inlägget. I det här avsnittet kommer jag att ge dig ett par länkar till länkar som innehåller mer information.

Introduktionsartiklar

Det här avsnittet innehåller ett par korta artiklar som presenterar begreppen och ger en översikt över de relaterade API:erna:

  1. Property getters and setters.
  2. JavaScript Getters and Setters

Mer avancerade artiklar

Dessa artiklar handlar om mer avancerade relaterade ämnen som de problem som getters och setters medför och hur man löser dem.

  1. Varför getters/setters är en dålig idé i JavaScript
  2. Datakapsling i JavaScript

Referensdokumentation

För att verkligen behärska ämnet finns slutligen länkarna till Mozilla-dokumentationen för de relaterade API:erna:

  1. get och set gör det möjligt att definiera getters och setters. Utöver vad vi förklarat här. Det finns andra intressanta funktioner som stöd för dynamiskt genererade egenskapsnamn och användning av getters och setters för att simulera att ställa in/hämta värden i en array
  2. seal och freeze gör det möjligt att styra vilka egenskaper hos ett objekt som kan ändras eller inte och hur. Det kan användas för att undvika att klienter använder föråldrade delar av ett objekts API.
  3. defineProperty gör det möjligt att definiera getters och setters och samtidigt ha mer kontroll över hur dessa egenskaper ses av klienter och hur modifierbara de är.

Lämna ett svar

Din e-postadress kommer inte publiceras.