Zapouzdření dat v JavaScriptu: gettery a settery
Při vytváření rozsáhlejších aplikací v JavaScriptu se brzy objeví potřeba rozdělit je do modulů propojených jasnými kontrakty. Pokud jde o dlouhodobou údržbu, je třeba zajistit způsob, jak zachovat kompatibilitu při změnách rozhraní. Za tímto účelem se objektově orientované jazyky spoléhají na zapouzdření neboli informaci skrývající implementační detaily před uživateli části kódu, aby se mohl změnit bez dopadu na klienty.
V tomto příspěvku si povíme o zapouzdření dat v jazyce JavaScript. Konkrétně si povíme o zapouzdřování vlastností za gettery a settery.
Několik pojmů
JavaScript byl navržen s principem kachního typování jako základ:
“Když vidím ptáka, který chodí jako kachna, plave jako kachna a kváká jako kachna, říkám mu kachna.”
Jinými slovy, JavaScript je ve své podstatě objektově orientovaný jazyk, ale na rozdíl od jiných objektově orientovaných jazyků, jako jsou C# a Java, jsou v JavaScriptu třídy občany druhé kategorie a rozhraní neexistují. Objekty nemají typy, a proto je třeba psát kód pro rozhraní k objektům, které mají určité vlastnosti a metody. Smlouvy mezi moduly jsou založeny na souboru metod a vlastností, o nichž se předpokládá, že jsou přítomny ve vyměňovaných objektech.
Zapouzdření je v objektově orientovaném programování zásadní. Znamená, že daný objekt by měl být schopen skrýt detaily svého vnitřního fungování, aby ostatní objekty, které s ním interagují, nebyly závislé na detailech jeho implementace, ale na dohodnutém rozhraní na vysoké úrovni. To zjednodušuje život vývojářům jak na straně poskytovatele, tak na straně uživatelů, protože oba vědí, že detaily implementace se mohou měnit, aniž by došlo k rozbití klientských objektů.
Proč je vystavování dat na rozhraní špatný nápad
V JavaScriptu je objekt jednoduše slovník jmen vlastností namapovaných na hodnoty, pokud je hodnotou vlastnosti funkce, nazýváme ji metoda. Rozhraní mezi metodami je množina vlastností, které klientský kód očekává, že na objektu najde.
Pokud objekt vystavuje pouze metody, je snadné, aby se rozhraní vyvíjelo s časem. Metoda může kontrolovat své parametry a podle toho reagovat. Je také možné vytvářet nové metody poskytující nové vlastnosti. A podporovat ty staré, které přizpůsobí staré chování na nové. U vlastností to možné není.
V případě vlastností není snadné udržet stabilní rozhraní. Klientský kód se totiž ve výchozím nastavení může odkazovat na neexistující vlastnosti objektu. Zápis do neexistující vlastnosti ji vytvoří. Její čtení vrátí nedefinovanou hodnotu. Klientský kód nebude schopen rychle zjistit, zda používá zastaralé vlastnosti. A co hůř, chyba se může rozšířit do dalších částí kódu, což ztíží odhalení problému.
Standardní API JavaScriptu má metody, které mohou být užitečné při předcházení takovým problémům: je možné zmrazit nebo zapečetit objekt, aby nebylo možné používat nepodporovaná jména vlastností.
Gettery/Setters, které zachrání situaci
Skrýt detaily implementace metody je snadné.
Gettery/setters byly do jazyka oficiálně zavedeny v ECMAScriptu 5.1 (ECMA-262). V současné době jsou podporovány ve všech hlavních desktopových a mobilních prohlížečích.
Základní myšlenka spočívá v tom, že se přidává syntaxe pro definování přístupových vlastností jako metod namísto jednoduchých datových vlastností. Getter je definován klíčovým slovem get následovaným funkcí pojmenovanou podle vlastnosti, která nepřebírá žádné argumenty a vrací hodnotu vlastnosti. Setter je definován klíčovým slovem set následovaným funkcí pojmenovanou po vlastnosti, která jako parametr přebírá novou hodnotu vlastnosti.
Následující příklad ilustruje getter a setter použité k definici přístupové vlastnosti s názvem 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);
Výstup:
042
Možno také vytvořit vlastnost pouze pro čtení definováním getteru bez setteru:
var obj = { get prop() { return -1; },};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);
Output:
-1-1
Vlastnost pak lze nahradit několika metodami, které v případě změny implementace třídy na ni mohou reagovat a přizpůsobit chování třídy. V nejhorším případě může vyvolat výjimku, která uživateli sdělí, že daná vlastnost je zastaralá a neměla by se již používat.
Další čtení
Doufám, že jste se v tomto příspěvku dozvěděli něco nového o navrhování komplexních evolučních aplikací v jazyce JavaScript. V této části vám poskytnu několik odkazů na odkazy obsahující další informace.
Úvodní články
Tato část přináší několik krátkých článků představujících koncepty a poskytujících přehled souvisejících rozhraní API:
- Property getters and setters.
- Gettery a settery v jazyce JavaScript
Pokročilejší články
Tyto články pojednávají o pokročilejších souvisejících tématech, jako jsou problémy, které přinášejí gettery a settery, a jak je řešit.
- Proč jsou gettery/settery v JavaScriptu špatný nápad
- Zapouzdření dat v JavaScriptu
Referenční dokumentace
Nakonec, abyste téma opravdu zvládli, odkazy na dokumentaci Mozilly k souvisejícím rozhraním API:
- get a set umožňují definovat gettery a settery. Nad rámec toho, co jsme zde vysvětlili. Existují i další zajímavé funkce, jako je podpora dynamicky generovaných názvů vlastností a použití getterů a setterů k simulaci nastavování/získávání hodnot v poli
- seal a freeze umožňují řídit, které vlastnosti objektu jsou či nejsou modifikovatelné a jak. Lze je použít k tomu, aby klienti nepoužívali zastaralé části API objektu.
- defineProperty umožňuje definovat gettery a settery a zároveň mít větší kontrolu nad tím, jak tyto vlastnosti vidí klienti a jak jsou modifikovatelné.
.