Adatkapszulázás JavaScriptben: getterek és setterek

Adatkapszulázás JavaScriptben: getterek és setterek

Ha nagyobb JavaScript-alkalmazásokat építünk, hamarosan szükségessé válik, hogy azokat egyértelmű szerződésekkel összekapcsolt modulokra osszuk. Amikor hosszú távú karbantartásról van szó, biztosítani kell a kompatibilitás fenntartásának módját a felületváltozások esetén. Ennek érdekében az objektumorientált nyelvek a kapszulázásra vagy az implementáció részleteit a felhasználók elől elrejtő információra támaszkodnak, hogy a kód a kliensek befolyásolása nélkül változhasson.

Ebben a bejegyzésben az adatok kapszulázásáról fogunk beszélni JavaScriptben. Pontosabban a getterek és setterek mögötti tulajdonságok kapszulázásáról fogunk beszélni.

Egy pár fogalom

A JavaScriptet a kacsatipizálás elvét alapul véve tervezték:

“Ha látok egy madarat, amely úgy jár, mint egy kacsa, úgy úszik, mint egy kacsa és úgy hápog, mint egy kacsa, akkor azt a madarat kacsának hívom.”

Más szóval, a JavaScript alapvetően objektumorientált nyelv, de más objektumorientált nyelvektől, például a C#-tól és a Javától eltérően a JavaScriptben az osztályok másodosztályú állampolgárok, és interfészek nem léteznek. Az objektumoknak nincsenek típusai, ezért kódot kell írni a bizonyos tulajdonságokkal és metódusokkal rendelkező objektumok interfészéhez. A modulok közötti szerződések azon metódusok és tulajdonságok halmazán alapulnak, amelyek feltételezhetően jelen vannak a kicserélt objektumokban.

A kapszulázás alapvető fontosságú az objektumorientált programozásban. Ez azt jelenti, hogy egy adott objektumnak képesnek kell lennie arra, hogy elrejtse belső működésének részleteit, hogy a vele kölcsönhatásba lépő más objektumok ne a megvalósításának részleteitől, hanem egy magas szinten elfogadott interfésztől függjenek. Ez egyszerűbbé teszi a fejlesztők életét, mind a szolgáltató, mind a felhasználók oldalán, mivel mindketten tudják, hogy a megvalósítás részletei változhatnak anélkül, hogy a kliensobjektumok tönkremenne.

Miért rossz ötlet az adatok felfedése egy interfészen

A JavaScriptben egy objektum egyszerűen egy értékekre leképezett tulajdonságnevek szótára, ha egy tulajdonság értéke egy függvény, akkor azt metódusnak nevezzük. A metódusok közötti interfész azoknak a tulajdonságoknak a halmaza, amelyeket a klienskód elvár egy objektumon.

Ha egy objektum csak metódusokat tár fel, akkor könnyű elérni, hogy az interfész idővel fejlődjön. Egy metódus ellenőrizheti a paramétereit, és ennek megfelelően reagálhat. Lehetőség van új funkciókat biztosító új metódusok létrehozására is. És, támogatva a régieket, amelyek a régi viselkedést adaptálják az újakra. A tulajdonságok esetében ez nem lehetséges.

A tulajdonságok esetében nem könnyű stabil interfészt tartani. Ugyanis alapértelmezés szerint az ügyfélkód hivatkozhat egy objektum nem létező tulajdonságaira. Egy nem létező tulajdonságra való írás létrehozza azt. Olvasása pedig definiálatlant fog visszaadni. Az ügyfélkód nem fogja tudni gyorsan felismerni, ha elavult tulajdonságokat használ. Ami még rosszabb, a hiba átterjedhet a kód más részeire, ami megnehezíti a probléma felismerését.

A szabványos JavaScript API rendelkezik olyan módszerekkel, amelyek hasznosak lehetnek az ilyen problémák elkerülésére: lehetőség van egy objektum befagyasztására vagy lezárására, hogy a nem támogatott tulajdonságneveket ne lehessen használni.

Getter/setterek mentik meg a helyzetet

A metódusimplementáció részleteinek elrejtése egyszerű.

A getterek/setterek hivatalosan az ECMAScript 5.1-ben (ECMA-262) kerültek be a nyelvbe. Jelenleg minden nagyobb asztali és mobil böngésző támogatja őket.

Az alapötlet az, hogy az egyszerű adattulajdonságok helyett szintaxissal egészíti ki a hozzáférési tulajdonságok metódusként való definiálását. A getter a get kulcsszóval definiálható, amelyet egy, a tulajdonságról elnevezett függvény követ, amely nem fogad el argumentumokat, és a tulajdonság értékét adja vissza. A setter a set kulcsszóval definiálható, amelyet egy, a tulajdonság után megnevezett függvény követ, amely paraméterként a tulajdonság új értékét veszi fel.

A következő példa egy getter és egy setter használatát mutatja be egy prop nevű accessor tulajdonság definiálásához:

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

Egy csak olvasható tulajdonságot is létrehozhatunk egy setter nélküli getter definiálásával:

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

Output:

-1-1

A tulajdonságot ezután néhány metódussal helyettesíthetjük, amelyek az osztály implementációjának változása esetén reagálhatnak erre, és adaptálhatják az osztály viselkedését. Legrosszabb esetben egy kivételt is fel tud dobni, hogy közölje a felhasználóval, hogy a tulajdonság elavult, és nem szabad többé használni.

További olvasmány

Remélem, ebben a bejegyzésben tanultál valami újat a komplex evolúciós alkalmazások JavaScriptben való tervezéséről. Ebben a részben adok néhány további információkat tartalmazó linket.

Bevezető cikkek

Ez a rész néhány rövid cikket tartalmaz, amelyek bemutatják a fogalmakat és áttekintést nyújtanak a kapcsolódó API-król:

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

Tovább haladó cikkek

Ezek a cikkek a kapcsolódó haladóbb témákról szólnak, például a getterek és setterek által hozott problémákról és azok megoldásáról.

  1. Miért rossz ötlet a getterek/setterek használata JavaScriptben
  2. Adatok kapszulázása JavaScriptben

Hivatkozási dokumentáció

Végül, hogy igazán elsajátítsuk a témát, a kapcsolódó API-k mozilla dokumentációjának linkjei:

  1. get és set lehetővé teszik a getterek és setterek definiálását. Túl azon, amit itt elmagyaráztunk. Vannak más érdekes funkciók is, mint például a dinamikusan generált tulajdonságnevek támogatása, valamint a getterek és setterek használata a tömbi értékek beállításának/megadásának szimulálására
  2. seal és freeze lehetővé teszi, hogy szabályozzuk, hogy egy objektum mely tulajdonságai módosíthatóak vagy nem és hogyan. Használható annak elkerülésére, hogy az ügyfelek egy objektum API-jának elavult részeit használják.
  3. defineProperty lehetővé teszi a getterek és setterek definiálását, ugyanakkor nagyobb kontrollt biztosít arra vonatkozóan, hogy ezeket a tulajdonságokat hogyan látják az ügyfelek és mennyire módosíthatóak.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.