Reklama

zonerbooks.cz | zoner.cz | czechia.com | regzone.cz | inshop.cz | inmail.cz | zonerpress.cz | zonerantivirus.com | zonerama.cz

interval.cz

Objektově orientované programování v JavaScriptu

06. 11. 2003 | Michal Kusýn | JavaScript a Ajax | Komentáře: 0

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.


Reklama


Další aktuální články na interval.cz

Tematicky související články

Dejte vědět i ostatním o článku

Diskuse (počet komentářů: 0)

Buďte prvním návštěvníkem, který přidá nový komentář.

Přidat nový komentář

Jméno a e-mail jsou nepovinné. Příspěvky obsahující odkaz jsou moderovány.

Zoner AntiVirus Free pro Android
zabezpečte si svůj smartphone, zdarma
Profesionální eshop Zoner inShop od 990 Kč.
Reklama
Reklama

Syndikace

hledáme nové autory | redakce interval.cz | reklama na interval.cz

© ZONER software, a.s., všechna práva vyhrazena, interval.cz dodržuje právní předpisy o ochraně osobních údajů. Powered by WordPress.