Objektově orientované programování v JavaScriptu
Pokud píšete v JavaScriptu jednodušší aplikace, postačí použít obyčejné strukturované programování a jednoúrovňové definice potřebných funkcí. Ovšem ne vždy může být takovýto styl optimální a především u rozsáhlejších programů zjistíte, že kód je stále nepřehlednější a logika zápisu poněkud pokulhává…
Ne nadarmo tedy už jistou řádku let existuje objektově orientované programování (OOP), známé především z C/C++ nebo jazyků Simula a Beta. I JavaScript zná pojmy OOP jako jsou instance, konstruktor, metoda či dědičnost, byť to není v pravém slova smyslu objektový jazyk. V následujícím článku vám povím něco o základech OOP v JS.
Objekty a třídy
Objektem, tak jako u jiných jazyků, míníme určitý soubor vlastností v jednom složeném datovém typu. Vlastnostmi daného objektu mohou být jak datové složky (proměnné), tak procedury, zvané metody. Chápání pojmu objekt v programování je zcela identické jako u objektů v reálném životě. Existuje-li nějaká konkrétní osoba, má své specifické datové složky, například věk
, pohlaví
a podobně. Umí-li dotyčná osoba sčítat, její metodou je secti(a,b)
.
Nejprve budu hovořit o objektech, jejichž charakteristickou vlastností je singularita, jinými slovy takový typ, který se v programu vyskytuje pouze jednou. Chceme-li pracovat s objektem Země
, pravděpodobně žádná další existovat nebude (alespoň zatím). Takovýto objekt můžeme vytvořit skrze literál objektu, jehož syntaxi můžete vidět níže. Výčtem se definují a inicializují jak proměnné objektu (pocet_lidi
), tak metody (otoc_doprava
), a při interpretaci JS dojde k okamžitému vytvoření požadovaného objektu. Všimněte si, že metody lze definovat jak přímo v literálu (otoc_doleva
), tak i mimo něj (otoc_doprava
). Přístup k jednotlivým vlastnostem je identický jako u objektů DOMu (tečková konvence).
function otoc() { alert(‚Otacim doleva‘); }
// Literal objektu
var zeme = {
pocet_lidi:“6 000 000 000″,
kontinenty : new Array(‚Amerika‘, ‚Asie‘),
otoc_doleva: otoc,
otoc_doprava: new Function(„alert(‚Otacim do prava)“)
};
// Vypise pocet lidi
alert(zeme.pocet_lidi);
// Otoci zemi doleva
zeme.otoc_doleva();
S podobným zápisem se můžete setkat u detektorů typu prohlížeče, které definují nový objekt browser
s logickými proměnnými reprezentujícími jednotlivé prohlížeče:
var browser = {
IE:(document.all)? true:false,
DOM:(document.getElementById)? true:false,
NS4:(document.layers)? true:false
};
// Je tento prohlizec NS4?
alert(browser.NS4);
Častější jsou ale případy, kdy je potřeba popsat určitý výsek reality, obsahujíc větší počet samostatných objektů stejného typu. Literály jsou jednocestná definice konkrétního objektu , provádějící se pouze při interpretaci JavaScriptu, tudíž tudy cesta nevede. Navíc přidávání nových objektů za běhu programu by bylo nemožné. V takovýchto případech využíváme definice vlastní struktury nového objektu, kterou lze nazvat třídou. Slovíčko „lze“ jsem použil záměrně, neboť se nejedná o definici třídy, tak ji známe např. z C++, ale přímo o definici inicializační funkce, takzvaného konstruktoru. Voláním konstruktoru pomocí operátoru new
se pak vytváří kýžené objekty, označované jako instance. V níže uvedeném zápise si také povšimněte, že vlastnost objektu se deklaruje přes klíčové slovo this
. Přímo při vytváření objektu lze přejímáním parametrů volaného konstruktoru inicializovat jednotlivé proměnné.
// Definice konstruktoru
function uzivatel(jmeno, prijmeni) {
this.jmeno = jmeno;
this.prijmeni = prijmeni;
this.vypisJmeno() = new Function(„alert(this.jmeno);“);
}
// Vytvoření nového uzivatele
novy_uzivatel = new uzivatel(„michal“, „kusyn“);
Dědičnost (inheritance)
Ačkoliv má JavaScript určité prvky dědičnosti, nejedná se o klasickou dědičnost známou z typových jazyků C/C++. Spíše můžeme mluvit o simulaci, neb JavaScript nepodporuje zápis tříd (pouze konstruktor) a s tím spojenou hierarchii tříd. Inheritance je u JavaScriptu tzv. prototypová. Prototyp je zvláštní objekt, který je přidružen každé funkci, tedy i k funkci konstruktoru. Všechny objekty inicializované skrze nějaký konstruktor dědí, respektive sdílejí, vlastnosti a metody obsažené v prototypu daného konstruktoru.
Podíváte-li se zpět na zápis konstruktoru uzivatel
, v objektu je vložená také metoda vypis()
Technicky má v paměti každá instance této „třídy“ lokální kopii této metody, což je přinejmenším z hlediska správy paměti nevhodné. Právě tento problém řeší prototypy, neboť stačí metodu deklarovat na úrovni prototypu a ta již nebude součástí každé instance. To ovšem neznamená, že nebude dosažitelná. Při vyhodnocování JavaScript hledá metodu nejprve v příslušném objektu, pakliže ji nenajde, jde o úroveň výše – do prototypu konstruktoru. Samozřejmě je vhodné sdílení pouze takových datových složek, které jsou neměnné pro všechny instance. To znamená především metody a konstanty. Jak by vypadal upravený zápis předchozího příkladu můžete vidět níže:
// Definice konstruktoru
function uzivatel(jmeno, prijmeni) {
this.jmeno = jmeno;
this.prijmeni = prijmeni;
}
uzivatel.prototype.vypisJmeno = new Function(„alert(this.jmeno);“);
Při hledání metod postupuje JS až k nejvyššímu nadřazenému objektu. Tím je obecný nadtyp Object
, zastřešující všechny ostatní objekty. Demonstrací předchozích tvrzení je konstrukce Object.prototype.server = "Interval.cz"
, která všem již existujícím nebo v budoucnu vytvořeným objektům „přiřadí“ vlastnost server
s příslušnou hodnotou. Nadtyp Object
lze využít i k další možné definici singulárních objektů. Diky tomu, že JS není přísně typový jazyk a vlastnosti můžeme přidávat dynamicky, lze objekty vytvářet i následujícím způsobem:
// Definice singularniho objektu zeme
zeme = new Object();
zeme.pocet_lidi = 6 000 000;
zeme.kontinenty = new Array(‚Amerika‘, ‚Evropa‘);
zeme.otoc_doprava = new Function(„alert(‚otacim do prava‘);“);
Systém dědičnosti nadřízených a podřízených tříd sice v JS neexistuje, ale pomocí prototypů ji lze úspěšně simulovat. Pravda, jedná se již o extrémní případ, ale jde to. Celý princip dědění spočívá v tvorbě nových prototypů. Máme-li třídu vesmirny_objekt
, třídu planeta
podřídíme tím, že přiřadíme konstruktoru planeta
jako prototyp objekt vesmirny_objekt
. Nevýhodou je fakt, že tímto způsobem nelze inicializovat hodnoty v nadřazené třídě prostřednictvím parametrů.
function vesmirny_objekt()
{
this.soustava = „slunecni“;
}
function planeta(pocet)
{
this.pocet_mesicu = pocet
}
planeta.prototype = new vesmirny_objekt();
zeme = new planeta(3);
alert(zeme.pocet_mesicu);
alert(zeme.soustava);
Objektové programování a DHTML
Nyní se konečně dostávám k využití OOP v DHTML aplikacích. Veškeré teoretické základy, uvedené výše, lze zužitkovat v zcela jiný styl programování. Ten spojí úroveň dokumentu a dat v jeden JavaScriptový objekt. Nespornou výhodou vytváření takovýchto homogenních prvků je přehlednější logika aplikace, spojení společných vlastností a metod v jeden celek, rozšiřitelnost a snadná úprava kódu. Nároky jsou hlavně při návrhu a realizaci jednotlivých objektů jistě vyšší, ale základní poučka OOP zní, že čím lépe a pečlivěji navrhnete systém tříd a jejich vlastností, tím snadněji lze realizovat běh programu.
Předpokládejme, že modelujeme situaci jisté databáze bookmarků na internetu. Databáze bude umět přidat nový odkaz a smazat vybrané odkazy. Databázi budeme považovat za singulární, zhotovíme ji výčtem. Odkazy naopak definujeme jako instance třídy. Důležitým faktorem je provázání s HTML dokumentem, se kterým databáze při výpisu uživatelů pracuje. Ostatní metody jsou již rutinou a provádějí činnosti odpovídající jejich názvu. Návrh realizace naleznete v dokumentu databaze.htm. Ukládáním dat se tentokrát zabývat nebudeme.
Výjimky
Poslední věcí, o které bych se rád zmínil, jsou výjimky. Ač to přímo nesouvisí s DHTML, toto téma je známé z objektově orientovaných jazyků, takže jen krátce předvedu podstatu věci. Jedná se o mechanismus zachytávání stavů, vyvolaných chybným kódem nebo, například, přístupem k neexistují metodě. Tyto chyby lze zachytávat pomocí klíčových slov try
, catch
a volitelně finaly
. Jejich syntaxe a popis je uvedena níže. Když jsem v úvodním díle o DHTML tajemně naznačil další způsob ošetřování různé podpory DOM, měl jsem na mysli právě zachytávání výjimek. Následující konstrukce u prohlížečů znající metodu document.implementation
nevyvolá žádnou reakci, zatímco u ostatních se zobrazí chybová hláška.
try {
// V tomto bloku se provadi kod ve kterem testujeme, zda-li nedojde k vyjimkce
s = document.implementation.hasFeature(‚HTML‘,’1.0′)
}
catch(e) {
// Tento blok obsauje kod, ktery se spusti, jestlize dojde v bloku try k vyjimkce
alert(‚Doslo k chybe. Vas prohlizec pravdepodobne nepodporuje nekterou z pouzivanych metod.‘);
}
finally {
// Kod bloku Finaly se vykona vzdy, at dojde k vyjimce nebo ne
}
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Umělá inteligence v IT
27. září 2023 -
Jak se chránit před podvody na internetu – část 1
8. října 2024 -
Thunderbolt 4 vs. OCuLink: Přišel čas na upgrade?
27. května 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024