inkapsling i JavaScript

detta blir mitt senaste inlägg i serien ”JavaScript for (C/)AL Developers” idag. Om jag fortsatte blogga om nästan rena JavaScript-saker, kan du rimligen fråga om det här faktiskt är en NAV-blogg eller en JavaScript. Det är fortfarande NAV, och medan de saker jag ska skriva om är rent ett JavaScript-koncept, tycker jag att det är mycket relevant för alla kontrolltilläggsutvecklare. Så, håll min öl, och bära med mig för en annan.

ett av de klagomål jag ofta hör om JavaScript är att i JavaScript finns det ingen inkapsling. Detta är nästan helt sant, förutom att det är helt falskt.

Var är problemet i första hand, och vad är då lösningen? Låt oss dyka in.

problemet

Föreställ dig att du förklarar en konstruktör. Föreställ dig för en sekund att vi befinner oss i ES5 world (som vi tyvärr måste använda om vi vill att våra kontrolltillägg ska vara helt kompatibla med alla plattformar där både NAV och Business Central stöds).

Detta är min kod:

uppenbarligen visar detta 42, vilket är min nuvarande ålder.

snart blir det min födelsedag, så det skulle visa sig 43:

nu, medan jag absolut skulle älska att kunna göra något liknande i verkliga livet:

… det kommer inte att hända. I en anständig objektorienterad värld bör” ålder ” vara en inkapslad egendom, och du borde inte kunna ringa vjeko.ålder = 25 alls. C # och” normala ” objektorienterade språk har ett koncept för inkapsling, de kan hantera detta med privata fält, men JavaScript har inget begrepp privat. Allt som definieras på detta inuti objektkonstruktören (eller senare på en instans av ett konstruerat objekt) är fullt tillgängligt för all kod som har tillgång till den instansen. I mitt exempel ovan, vem som helst kan ställa in ålder och komma undan med det.

man kan säga att JavaScript inte har någon inkapsling. Och som jag sa ovan, du skulle vara helt fel.

lösningen

så uppenbart som det är att vi inte kan förklara någonting som privat direkt, det finns fortfarande saker vi kan använda. Ett vackert koncept som är praktiskt kallas stängningar. Stängningar förklaras långt på en miljon bloggar, dokumentationswebbplatser och kodexempel över hela internet, och du kan google bejesus ur dem i din egen takt, så jag kommer inte att fördjupa mig i att förklara stängningar här. Jag hoppar helt enkelt direkt in i att tillämpa dem för att lösa inkapslingsproblemet.

det finns åtminstone två sätt hur du kan hantera detta. Låt oss först göra det mer uppenbara: en åtkomstfunktion.

Föreställ dig världen utan egenskaper där du inte kan göra objekt.egenskap = värde (som vjeko.ålder = 25 i vårt fall, så mycket som jag skulle älska det!). I den världen skulle du ha getter och setter funktioner:

(ignorera för ett ögonblick det faktum att jag fortfarande använder detta.”egenskapen”)

självklart skulle du kunna kalla dessa så här:

sedan, om du ville ha ålder som skrivskyddad, skulle du helt enkelt släppa setAge setter-funktionen. Om detta.ålder var verkligen privat (vilket det inte är), det skulle göra tricket för dig. Problemet är att inget definierat på detta är privat, det är tillgängligt för alla som har tillgång till någon instans av objektet. Det är så offentligt som det blir.

för att åtgärda detta problem är det första vi behöver göra att flytta getter-funktionsdeklarationen från prototypen till instansen. Prototypmedlemmar är närmast vad vi skulle kalla statiska i C#, även om de under körning har vissa beteendeegenskaper hos både statiska och instansmedlemmar. Låt oss dock först flytta medlemmen bort från prototypen och till instans:

detta löser bara den första delen av problemet, det faktum att getAge definierades på prototypen snarare än på instansen. Men med en enkel förändring som denna:

… vi löser problemet helt:

ålder är nu helt inkapslad. Du kan komma åt den via getter-funktionen, men du kan inte ställa in den direkt eftersom den bara är tillgänglig i stängningsomfånget för detta.getAge instans funktion.

för att fullt ut implementera Personklassen måste du flytta growOlder-funktionen från prototypen till instansen:

och det fungerar precis som du vill att det ska fungera:

men varför fungerar det? Det fungerar på grund av nedläggningar. Åldersparametern från konstruktören fångades i stängningsomfånget för både getAge-och growOlder-funktioner, så att du kan komma åt dess värde från båda dessa funktioner, men gör det helt otillgängligt för någon annan, någon annanstans.

ännu bättre lösning

du kan säga att du inte vill komma åt den via en getter-funktion, och att du behöver fullblåst skrivskyddad egenskapssyntax. Du vill ha din ålder skrivskyddad och inkapslad samtidigt. Jag har dig! JavaScript kan inte kapsla in det! Förutom att det absolut kan.

jag adresserade objektet.defineProperty metod i mitt tidigare inlägg, och om du läser det, kan du omedelbart se hur det kan tillämpas här.

så, låt oss definiera en skrivskyddad instansegenskap för Personklass:

där. Det gjorde inte ont. Och det fungerar:

så där har du det. Fullblåst inkapsling i JavaScript för att hjälpa dig att skriva bra, isolerad kod och ta dina kontrolltillägg till real kick-a$$ nivå.

Glad JavaScripting, och jag hoppas få mer tid att blogga om andra coola och användbara JavaScript tips och tricks för (C/)al Utvecklare.

Lämna ett svar

Din e-postadress kommer inte publiceras.