Internet Info, s.r.o. Lupa Měšec Podnikatel Root Zdroják DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Třídy, dědičnost a OOP v Javascriptu - I

Jak funguje objektově orientované programování v Javascriptu? Má Javascript třídy nebo nemá? Jak se implementuje dědičnost? Na tyto otázky si odpovíme v sérii článků, a ukážeme si, že Javascript je flexibilní, objektově orientovaný jazyk, vhodný nejen pro rychlé prototypování, ale i pro vývoj složitých aplikací.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

Začneme stručným shrnutím a sjednocením pojmů, kterým se v našem výkladu nevyhneme, a poznámkami k textu.

Pokud vás nějaký aspekt jazyka zaskočí, nebo pokud se vám bude zdát, že jsem něčemu nevěnoval dostatečnou pozornost, doporučuji odkaz: https://developer.mozilla.org/en/JavaScript, který by si měl uložit každý, kdo to s Javascriptem myslí vážně. 

Na všechny příklady budeme používat službu jsFiddle, díky které si můžete příklady rovnou naživo vyzkoušet.

Českou terminologii použiji, pouze existuje-li ustálený český ekvivalent. Nesouhlasím s nutností překladu do češtiny za každou cenu, ba co víc, domnívám se, že je to činnost zbytečná a škodlivá. Bez znalosti angličtiny se programátor stejně neobejde.

Ačkoliv budu psát o dědičnosti a objektově orientovaném programování, zmíním i funkcionální prvky jazyka. Martin Malý mi kdysi položil otázku: Je nějaký důvod, proč by lidi v JavaScriptu měli programovat především „objektově“ a ne „funkcionálně“? Tato otázka klade falešné dilema. Nejlepší je znát a využívat oba přístupy, a ty rozhodně nejsou zaměnitelné, spíše se doplňují. Doufám, že na konci minisérie bude zřejmé jak. Ukážeme si všechny obvyklé způsoby, jak vytvořit "třídu", a to od nejjednoduššího po nejsprávnější.

Tak má ten Javascript třídy, nebo nemá?

Jak by řekl sir Humphrey, ano i ne. Javascript nemá klasické třídy. Avšak podle definice "A class is a construct that is used as a blueprint (or template) to create objects of that class." (in: http://en.wikipedia.org/wiki/Class_(computer_science)) třídy má. Mezi programátory Javascriptu pak platí konsensus, že za třídu považujeme konstrukční funkci, krátce konstruktor, který využívá vlastnosti prototype. Jak se taková konstrukční funkce s vlastností prototype liší od klasické třídy, si povíme v průběhu článku.

Přehled pojmů

Scope a closure

Upozornění: Podrobně se tématu věnoval Petr Staníček ve svém seriálu. Já jej zde opakuji pro osvěžení a také proto, že další úhel pohledu nikdy není na škodu.

Scope je rozsah viditelnosti proměnné. Scope může být globální nebo lokální. Globální scope je jeden, a v prohlížeči jej vždy reprezentuje objekt window. Lokální scope generuje v Javascriptu pouze funkce. Scope si lze představit jako mercedes s tmavými skly. Zevnitř je vidět ven, ale zvenčí není vidět dovnitř. Javascript umožňuje do sebe funkce zanořovat. Tím se tvoří scope chain. Tady už příklad trochu kulhá, ale dejme tomu, že zaparkujeme mercedes v garáži, která má okna také ztmavená. Viz příklad Scope.

Closure je pouze jiný název pro scope. Když hovoříme o closure nějaké funkce, hovoříme o scope, ve kterém byla funkce deklarována. Proč je vnější scope funkce tak důležitý, že si zasluhuje vlastní název? Je to proto, že je na něj zevnitř funkce vidět, ať už funkci voláme z jakéhokoliv místa v programu. To je velmi užitečné, protože v Javascriptu jsou funkce prvotřídní objekty. To zhruba znamená, že si je můžeme ukládat do proměnných nebo předávat argumentem, čili zacházet s nimi jako s objekty. Funkce si vždy nese odkaz na scope, ve kterém byla deklarována. Zanořování funkcí a to, že každá funkce má vlastní closure, jsou funkcionální prvky jazyka Javascript.Viz názorný příklad Closure.

Objekt

V Javascriptu platí, že vše co není primitivní typ je asociativní pole, krátce objekt. Funkce je objekt, pole je objekt, i regulární výraz je objekt. Pro začátečníky bývá matoucí, že vše je objekt, tedy asociativní pole, a přesto existuje samostatný typ object. Jak je to možné? Je to jednoduché: Object je v hierarchii všech typů nejvýše, je tedy předkem pro všechny ostatní typy, díky čemuž všichni jeho potomci dědí jeho vlastnosti. Objekt je zkrátka v Javascriptu vše, co umožňuje přiřadit vlastnost, a předává se referencí.

http://jsfiddle.net/V7a7x/

Funkce, metoda, konstruktor, třída

Vše, co je zmíněno v titulku, je v Javascriptu stále a jedna tatáž funkce. Proč jí tedy nazýváme čtyřmi jmény? Protože pojmenování určuje roli, kterou funkce hraje. V Javascriptu funkce slouží k více účelům.

Funkce, to je prostá definice. Není přiřazena k žádné třídě, k žádnému objektu, a podle konvence se píše v camelCase, tedy s malým písmenem na začátku.

var foo = function () {};

Pokud je funkce přiřazena nějakému objektu, říkáme jí Metoda. Rovněž ji píšeme v camelCase.

user.foo();

Konstruktor, neboli konstrukční funkce, je určena k vytváření instancí. Proto se jí také říká třída. Třída a konstruktor znamená v Javascriptu to samé. Píšeme ji v PascalCase, tedy s velkým písmenem na začátku, které nám naznačí, že bychom měli použít operátor new.

var Person = function() {};
var joe = new Person();

this, kontext

Klíčové slovo this odkazuje na kontext. Kontext je objekt, ve kterém funkci voláme. V následujícím příkladu vidíme, že voláme-li funkci bane přímo, je kontextem globální objekt window. Přiřadíme-li funkci objektu user, stane se kontextem user. Jak tečkový operátor přesně funguje, si povíme později.

var bane = function() {
    this.banned = true;
};
bane();

// true
alert(window.banned);

var user = {};
user.bane = bane;
user.bane();

// true
alert(user.banned);​

Příklad: http://jsfiddle.net/Nz9TJ/

Jak je vidět, funkce můžeme volat nad různými objekty. Většinou hovoříme o kontextu, ve kterém je funkce volána. Kontext můžeme funkci i vnutit, pomocí klíčových slov call a apply, jak ukazuje následující příklad: http://jsfiddle.net/KnaWr/

Techniky vytváření tříd

Ukážeme si dvě falešné a jednu správnou. Falešné, protože ve skutečnosti nejde o vytváření instancí tříd, ale o konstrukci podobných objektů. Jaký je v tom rozdíl, nám postupně osvětlí příklady.

Zneužití closure

// zajímavý, avšak špatný způsob vytváření "instancí" v Javascriptu
var Animal = function(p_name) {
    var name = p_name;
    return {
        showName: function() {
            alert(name);
        }
    }
};
var kitty = Animal('Kitty'); 
// alert 'Kitty'
kitty.showName();

// false
alert(kitty instanceof Animal);

Příklad: http://jsfiddle.net/4CXkY/

Popíšeme si, co vidíme. Funkce Animal přijímá parametr p_name, který si ukládá do lokální proměnné name. Následně vrací objekt s metodou showName, která vidí lokální proměnnou name ve svém closure. Na dalším řádku vytvářím "instanci" kitty. Všimněte si, bez použití operátoru new. Ten je v tomto případě zcela zbytečný, objekt, který funkce Animal vrací, si vytvářím sám. Na posledním řádku vidíme využití "instance" v praxi. Každá instance je unikátní, každá má vlastní scope (v něm je uložena proměnná name). Proměnná name je zapouzdřena, protože je lokální, nelze ji změnit odjinud, než z vnitřku funkce Animal.

"Hurá!, to bylo jednoduché. Takhle jednoduše, že se dělají třídy? V tom případě mám hotovo, ještě napsat testy, podědit a... a sakra, co když budu mít privátní metodu, jak ji otestuji? Nijak, no nic. Teď musím ještě vytvořit "třídu" Cat, potomka třídy Animal... hmm, jenže jak? Možná, že kdybych..."

Stop, takhle ne! Výše uvedený příklad ilustruje pružnost Javascriptu, ale rozhodně není správným způsobem, jak tvořit třídy. Ukázali jsme si jej proto, že naznačuje obvyklý způsob, jakým se v Javascriptu imitují privátní proměnné, totiž pomocí lokálních proměnných schovaných v closure.

"Privátní" proměnné v Javascriptu - má to smysl?

Každý javascriptový programátor by si měl uvědomit, že snaha ultimátně zapouzdřit nějakou proměnou, či rovnou celou funkcionalitu, je většinou marná. Javascript je dynamický jazyk. Pokud do své aplikace pustíme cizí kód, o kterém nevíme, co dělá, a proto raději "zapouzdřujeme", trpíme falešným pocitem bezpečí. Smiřme se s faktem, že Javascript není vhodný jazyk pro psaní software na ovládání jaderných elektráren, a zkusme to brát jako jeho výhodu.

Pokud v Javascriptu něco "zapouzdřujeme", děláme to hlavně proto, abychom čtenáři kódu naznačili: "Tohle je privátní, tak si toho nevšímej. Nespoléhej, že tahle metoda bude vždy fungovat stejně, možná v příští verzi nebude fungovat vůbec." Mírně to naznačíme podtržítkem v názvu, brutálně pomocí closure. Jestli někde má smysl simulovat privátní proměnné pomocí closure, tak jedině u statických objektů, tedy modulů.

Moduly

Modul v Javascriptu rovná se statický objekt. Nelze vytvářet jeho instance. Implementace snad ani nemůže být jednodušší.

var console = {
    log: function(message) {
        // ... nějaký kód
    }
};

Douglas Crockford "vymyslel" vlastní verzi modulu, která má, považte, privátní lokální proměnné.

var console = (function() {
    var iAmPrivate = 'foo';    
    return {
        log: function(message) {
            // ... nějaký kód
        }
    }
})();

Popišme si kód: Vytváříme anonymní funkci, kterou okamžitě voláme (ty kulaté závorky na konci). Vnitřní scope anonymní funkce je closure metody log. Metoda log je v objektu, který vracíme, a který se ukládá do proměnné console. Je nemožné z vnějšku změnit proměnnou iAmPrivate, zato je velmi jednoduché přepsat objektu console metodu log. Proto je hra na "privátní" proměnné v Javascriptu převážně čas mařící manýrou. Přesto se tato technika občas používá, a to ze dvou rozumných důvodů:

  1. potřebujeme referenční proměnné, a nechceme špinit globální scope
  2. mikrooptimalizace

jQuery je knihovna, která se maximálně vyhýbá znečištění globálního scope. Fakticky má pouze dvě globálně viditelné proměnné, jQuery a $. Dolar si však jako globální magickou über funkci vybralo více knihoven. Proto jQuery navrhuje vlastní  kód zapouzdřit takto:

(function($) {
    /* some code that uses $ */ 
})(jQuery);

Začátečník (a, co si budeme namlouvat, i profesionál), je rád, že namísto dlouhého j Q u e r y, může všude psát sexy dolary, aniž by riskoval konflikt s jinou knihovnou.

Druhým, a jen zřídka rozumným, důvodem jsou mikrooptimalizace (premature optimization is the root of all evil). 

(function() {
    var EventType = SomeNamespace.InnerNamespace.ClassName.EventType;
})();

Jak lze vidět, vytváříme si lokální referenci na EventType nějaké třídy. Kdykoliv budeme enumeraci EventType potřebovat, odkážeme se na lokální proměnnou. Javascript tak nebude vyhodnocovat x tečkových operátorů stále dokola. Toto má smysl, pokud chceme "zpřehlednit" kód, a také, pokud nám záleží na tom, aby funkce využívající EventType, byla zhruba o tisícinu milisekundy rychlejší. Někdy to smysl má, protože Internet Explorer. Ale pouze pro výkonnostně kritické funkce, například $type ($type je funkce pro detekci všech možných typů, se kterými se můžeme v Javascriptu setkat). K modulům se ještě vrátíme, až budeme probírat mixování.

"Vylepšené" třídy

Následující příklad už vypadá lépe. Je tam operátor new (ten za nás vytváří objekt), používá se this (tím se na vytvořený objekt odkazujeme uvnitř metody), operátor instanceof funguje. Je to technika navržená Douglasem Crockfordem. Douglas si dokonce vytvořil vlastní názvosloví: metodě showName se říká privilegovaná, protože ačkoli je veřejná, má přístup k privátní lokální proměnné name. Douglas Crockford udělal pro svět Javascriptu hodně, ale některé články, věnované OOP a dědičnosti, se mu zrovna nepovedly. Ani tento způsob není správný:

var Animal = function(p_name) {
    var name = p_name;
    // privilegovaná metoda
    this.showName = function() {
        alert(name);
    }
};
var kitty = new Animal('Kitty');
kitty.showName(); // 'Kitty' 
alert(kitty instanceof Animal); // true

(http://jsfiddle.net/EP7Mw/)

Předchozí příklad "zneužití closure" i tento mají společné, že ukazují "konečně ten správný" postup, jak mít v Javascriptu privátní členy. A oba jsou špatné. Privátní členy můžeme akceptovat u modulů, ale tvořit třídy tímto způsobem nelze. Vzdejte to. Funkcionální prvky Javascriptu mají své využití jinde. Možná vám vrtá hlavou, proč jsou předchozí techniky špatné. Každá nakonec selže na jednom z těchto bodů:

  • privátní lokální proměnné a metody neotestujete
  • closure a privilegované metody se pro každou instanci vytváří zas a znova, což je nemalá (a hlavně zbytečná) zátěž
  • nefunguje operátor instanceof
  • veškerá legrace skončí, až se pokusíte podědit takovou "třídu"
    • v potomku nelze volat metodu rodiče
    • již existující instanci nelze (elegantně) přidat nebo změnit vlastnost

Konec první části

Ukázali jsme si několik metod, jak v Javascriptu vytvářet objekty, představili jsme si jejich výhody a nevýhody, řekli si, kde se používají, a především - proč jsou špatné. V příští části se podíváme na "konečně správné" řešení pomocí prototype.

Nepřehlédněte!

Autor článku Daniel Steigerwald vystoupí s přednáškou na téma Třídy, dědičnost a OOP v Javascriptu na letošní konferenci Internet Developer Forum 2010. Přijďte si jej (a samosebou i další přednášející) poslechnout a zeptat se jich na to, co vás zajímá, ve středu 7. dubna do Národní technické knihovny (registrace nutná).

Daniel Steigerwald

Autor je AJAX a .NET programátor na volné noze specializující se na složité Javascriptové aplikace, které jsou mu výzvou. Je autorem služby AMapy.cz včetně API.

Školení Google+ pro firmy

DW - Školení PPC
  • Jak využít Google+ pro firemní komunikaci a marketing.
  • Čím se liší Google+ od Twitteru a Facebooku z pohledu firemního využití.
  • Jak využít Google+ v souladu s pravidly užívání.
  • Založení Google+ Page (Stránky) krok po kroku, včetně praktických tipů.

Detailní informace o školení Google+ »

Přehled názorů

Odkdy funkce není objektem?
gisat 15. 3. 2010 00:54
Nový
├ 
Re: Odkdy funkce není objektem?
Daniel Steigerwald 15. 3. 2010 01:18
Nový
└ 
Re: Odkdy funkce není objektem?
peter 15. 3. 2010 01:27
Nový
 
└ 
Re: Odkdy funkce není objektem?
Daniel Steigerwald 15. 3. 2010 01:32
Nový
 
 
└ 
Re: Odkdy funkce není objektem?
olin 15. 3. 2010 07:49
Nový
Odpověď na dotaz Daniela Steigerwalda
Jiří Hrebenar 15. 3. 2010 03:28
Nový
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aleš Roubíček 15. 3. 2010 06:41
Nový
│
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
peter 15. 3. 2010 09:32
Nový
│
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aleš Roubíček 15. 3. 2010 10:27
Nový
│
│
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Peter Rybar 15. 3. 2010 13:00
Nový
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Jiří Hrebenar 15. 3. 2010 12:09
Nový
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aichi 15. 3. 2010 10:44
Nový
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Jiří Hrebenar 15. 3. 2010 12:14
Nový
│
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aichi 15. 3. 2010 12:20
Nový
│
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Jiří Hrebenar 15. 3. 2010 13:41
Nový
│
 
 
 
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aleš Roubíček 15. 3. 2010 13:52
Nový
│
 
 
 
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Michal Augustýn 15. 3. 2010 14:05
Nový
│
 
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Daniel Steigerwald 15. 3. 2010 14:10
Nový
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
jay 15. 3. 2010 11:01
Nový
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Jiří Hrebenar 15. 3. 2010 11:34
Nový
│
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
jay 15. 3. 2010 15:41
Nový
│
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
MD 15. 3. 2010 16:19
Nový
│
 
 
 
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Vít Šesták (v6ak) 15. 3. 2010 16:22
Nový
│
 
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Peter Rybar 15. 3. 2010 16:27
Nový
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Daniel Steigerwald 15. 3. 2010 13:15
Nový
│
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
MD 15. 3. 2010 13:30
Nový
│
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Daniel Steigerwald 15. 3. 2010 13:48
Nový
│
 
 
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aleš Roubíček 15. 3. 2010 13:54
Nový
│
 
 
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Michal Augustýn 15. 3. 2010 14:07
Nový
│
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
MD 15. 3. 2010 15:04
Nový
│
 
 
 
├ 
Re: Odpověď na dotaz Daniela Steigerwalda
Aleš Roubíček 15. 3. 2010 15:11
Nový
│
 
 
 
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
Daniel Steigerwald 15. 3. 2010 15:21
Nový
└ 
Re: Odpověď na dotaz Daniela Steigerwalda
pk 16. 3. 2010 11:27
Nový
Pěkný článek + malá výtka k testům
Aleš Roubíček 15. 3. 2010 06:49
Nový
├ 
Re: Pěkný článek + malá výtka k testům
Michal Augustýn 15. 3. 2010 08:22
Nový
└ 
Re: Pěkný článek + malá výtka k testům
Daniel Steigerwald 15. 3. 2010 11:58
Nový
 
└ 
Re: Pěkný článek + malá výtka k testům
Aleš Roubíček 15. 3. 2010 13:07
Nový
 
 
└ 
Re: Pěkný článek + malá výtka k testům
MD 15. 3. 2010 13:26
Nový
 
 
 
├ 
Re: Pěkný článek + malá výtka k testům
Aleš Roubíček 15. 3. 2010 13:36
Nový
 
 
 
└ 
Re: Pěkný článek + malá výtka k testům
Borek Bernard 17. 3. 2010 01:26
Nový
struktura + ladění anonymních funkcí + těšení
Michal Augustýn 15. 3. 2010 08:37
Nový
├ 
Re: struktura + ladění anonymních funkcí + těšení
Tom5 15. 3. 2010 08:44
Nový
│
└ 
Re: struktura + ladění anonymních funkcí + těšení
Martin Malý 15. 3. 2010 09:39
Nový
│
 
└ 
Re: struktura + ladění anonymních funkcí + těšení
Karel 16. 3. 2010 09:53
Nový
├ 
Re: struktura + ladění anonymních funkcí + těšení
Ondřej Žára 15. 3. 2010 09:37
Nový
│
└ 
Re: struktura + ladění anonymních funkcí + těšení
Daniel Steigerwald 15. 3. 2010 17:14
Nový
│
 
└ 
Re: struktura + ladění anonymních funkcí + těšení
Ondřej Žára 15. 3. 2010 21:45
Nový
└ 
Re: struktura + ladění anonymních funkcí + těšení
Daniel Steigerwald 15. 3. 2010 16:51
Nový
 
├ 
Re: struktura + ladění anonymních funkcí + těšení
Michal Augustýn 15. 3. 2010 17:01
Nový
 
└ 
Re: struktura + ladění anonymních funkcí + těšení
Aleš Roubíček 15. 3. 2010 19:46
Nový
funkce objekt/neobjekt?
MD 15. 3. 2010 10:30
Nový
├ 
Re: funkce objekt/neobjekt?
Ondřej Žára 15. 3. 2010 10:35
Nový
└ 
Re: funkce objekt/neobjekt?
Daniel Steigerwald 15. 3. 2010 12:14
Nový
clanok
Mazarik 15. 3. 2010 11:44
Nový
└ 
Re: clanok
Daniel Steigerwald 15. 3. 2010 12:18
Nový
povedený článek
Petr Bíža 15. 3. 2010 11:55
Nový
└ 
Re: povedený článek
Daniel Steigerwald 15. 3. 2010 12:06
Nový
Thumbs up
bzuK 15. 3. 2010 12:07
Nový
Pochvala
Matyáš Novák 15. 3. 2010 12:22
Nový
Moc pěkné
danaketh 15. 3. 2010 13:34
Nový
vyborne
aprilchild 15. 3. 2010 13:37
Nový
pohled na článek
Martin Staněk 15. 3. 2010 13:55
Nový
├ 
Re: pohled na článek
aprilchild 15. 3. 2010 14:07
Nový
│
└ 
Re: pohled na článek
Martin Staněk 15. 3. 2010 15:05
Nový
│
 
├ 
Re: pohled na článek
Aleš Roubíček 15. 3. 2010 15:32
Nový
│
 
└ 
Re: pohled na článek
karmi 15. 3. 2010 15:33
Nový
└ 
Re: pohled na článek
Daniel Steigerwald 15. 3. 2010 15:37
Nový
 
├ 
Re: pohled na článek
Martin Staněk 15. 3. 2010 16:43
Nový
 
└ 
Re: pohled na článek
Martin Malý 20. 3. 2010 00:26
Nový
Oh!!
s 15. 3. 2010 13:58
Nový
├ 
Re: Oh!!
Michal Augustýn 15. 3. 2010 14:09
Nový
└ 
Re: Oh!!
Peter Rybar 15. 3. 2010 14:17
Nový
 
└ 
Re: Oh!!
s 15. 3. 2010 14:27
Nový
 
 
└ 
Re: Oh!!
Peter Rybar 15. 3. 2010 14:32
Nový
 
 
 
└ 
Re: Oh!!
s 15. 3. 2010 14:41
Nový
 
 
 
 
└ 
Re: Oh!!
Peter Rybar 15. 3. 2010 14:48
Nový
Článek
Rene 15. 3. 2010 14:49
Nový
Proč privátně?
Vít Šesták (v6ak) 15. 3. 2010 18:29
Nový
├ 
Re: Proč privátně?
Daniel Steigerwald 15. 3. 2010 20:24
Nový
│
└ 
Re: Proč privátně?
Vít Šesták (v6ak) 15. 3. 2010 20:57
Nový
│
 
└ 
Re: Proč privátně?
Daniel Steigerwald 15. 3. 2010 21:04
Nový
│
 
 
└ 
Re: Proč privátně?
Vít Šesták (v6ak) 15. 3. 2010 21:08
Nový
└ 
Re: Proč privátně?
Michal Augustýn 15. 3. 2010 20:24
Nový
 
├ 
Re: Proč privátně?
Daniel Steigerwald 15. 3. 2010 20:31
Nový
 
│
└ 
Re: Proč privátně?
Daniel Steigerwald 15. 3. 2010 20:34
Nový
 
│
 
└ 
Re: Proč privátně?
Michal Augustýn 15. 3. 2010 20:39
Nový
 
│
 
 
└ 
Re: Proč privátně?
junix 18. 3. 2010 13:37
Nový
 
└ 
Re: Proč privátně?
Aichi 16. 3. 2010 10:44
Nový
Struktura článku
David 15. 3. 2010 21:47
Nový
└ 
Re: Struktura článku
Daniel Steigerwald 15. 3. 2010 22:24
Nový
 
└ 
Re: Struktura článku
David 15. 3. 2010 23:52
Nový
Špatný článek
Bauglir 16. 3. 2010 02:00
Nový
├ 
Re: Špatný článek
David Grudl 16. 3. 2010 03:46
Nový
│
├ 
Re: Špatný článek
Peter Rybar 16. 3. 2010 11:50
Nový
│
├ 
Re: Špatný článek
koroptev 16. 3. 2010 12:20
Nový
│
└ 
Re: Špatný článek
peter 17. 3. 2010 00:07
Nový
└ 
Re: Špatný článek
Daniel Steigerwald 16. 3. 2010 04:18
Nový
 
├ 
Re: Špatný článek
xx 16. 3. 2010 10:19
Nový
 
│
└ 
Re: Špatný článek
Peter Rybar 16. 3. 2010 11:54
Nový
 
│
 
└ 
Re: Špatný článek
Jakub Nešetřil 16. 3. 2010 13:03
Nový
 
│
 
 
├ 
Re: Špatný článek
Peter Rybar 16. 3. 2010 13:40
Nový
 
│
 
 
├ 
Re: Špatný článek
Bauglir 16. 3. 2010 13:45
Nový
 
│
 
 
└ 
Re: Špatný článek
xx 16. 3. 2010 14:19
Nový
 
│
 
 
 
├ 
Re: Špatný článek
Aleš Roubíček 16. 3. 2010 14:38
Nový
 
│
 
 
 
│
└ 
Re: Špatný článek
xx 16. 3. 2010 15:29
Nový
 
│
 
 
 
└ 
Re: Špatný článek
koroptev 16. 3. 2010 14:40
Nový
 
└ 
Re: Špatný článek
Bauglir 16. 3. 2010 12:22
Nový
 
 
├ 
Re: Špatný článek
Daniel Steigerwald 16. 3. 2010 14:28
Nový
 
 
└ 
Re: Špatný článek
olin 17. 3. 2010 00:04
Nový
jiny jazyk
MD 16. 3. 2010 08:28
Nový
├ 
Re: jiny jazyk
Ondřej Žára 16. 3. 2010 08:38
Nový
│
└ 
Re: jiny jazyk
Peter Rybar 16. 3. 2010 12:08
Nový
└ 
Re: jiny jazyk
koroptev 16. 3. 2010 12:55
Nový
se pridam ke kritice
koroptev 16. 3. 2010 11:25
Nový
└ 
Re: se pridam ke kritice
David Grudl 16. 3. 2010 11:40
Nový
 
├ 
Re: se pridam ke kritice
koroptev 16. 3. 2010 12:06
Nový
 
│
└ 
Re: se pridam ke kritice
olin 16. 3. 2010 23:46
Nový
 
└ 
Re: se pridam ke kritice
Peter Rybar 16. 3. 2010 12:18
Nový
 
 
└ 
Re: se pridam ke kritice
koroptev 16. 3. 2010 12:23
Nový
 
 
 
└ 
Re: se pridam ke kritice
peter 17. 3. 2010 00:19
Nový
 
 
 
 
└ 
Re: se pridam ke kritice
Daniel Steigerwald 17. 3. 2010 13:54
Nový
 
 
 
 
 
└ 
Re: se pridam ke kritice
peter 17. 3. 2010 14:25
Nový
 
 
 
 
 
 
├ 
Re: se pridam ke kritice
Michal Augustýn 17. 3. 2010 15:24
Nový
 
 
 
 
 
 
│
└ 
Re: se pridam ke kritice
peter 17. 3. 2010 18:23
Nový
 
 
 
 
 
 
│
 
├ 
Re: se pridam ke kritice
Daniel Steigerwald 17. 3. 2010 18:57
Nový
 
 
 
 
 
 
│
 
│
└ 
Re: se pridam ke kritice
paranoiq 18. 3. 2010 18:01
Nový
 
 
 
 
 
 
│
 
│
 
└ 
Re: se pridam ke kritice
belzebub 14. 4. 2010 19:09
Nový
 
 
 
 
 
 
│
 
└ 
Re: se pridam ke kritice
Michal Augustýn 18. 3. 2010 02:06
Nový
 
 
 
 
 
 
└ 
Re: se pridam ke kritice
Daniel Steigerwald 17. 3. 2010 15:27
Nový
OOP, dedicnost
junix 17. 3. 2010 17:15
Nový
└ 
Re: OOP, dedicnost
Daniel Steigerwald 17. 3. 2010 17:56
Nový
 
├ 
Re: OOP, dedicnost
junix 17. 3. 2010 18:26
Nový
 
│
├ 
Re: OOP, dedicnost
Vít Šesták (v6ak) 17. 3. 2010 18:38
Nový
 
│
└ 
Re: OOP, dedicnost
Daniel Steigerwald 17. 3. 2010 18:53
Nový
 
│
 
└ 
Re: OOP, dedicnost
junix 17. 3. 2010 23:52
Nový
 
└ 
Re: OOP, dedicnost
aprilchild 17. 3. 2010 21:33
Nový
 
 
├ 
Re: OOP, dedicnost
Timy _ 18. 3. 2010 01:16
Nový
 
 
│
└ 
Re: OOP, dedicnost
aprilchild 18. 3. 2010 12:26
Nový
 
 
│
 
└ 
Re: OOP, dedicnost
Daniel Steigerwald 18. 3. 2010 15:21
Nový
 
 
└ 
Re: OOP, dedicnost
Daniel Steigerwald 20. 3. 2010 23:23
Nový
 
 
 
└ 
Re: OOP, dedicnost
Petr Krontorad 21. 3. 2010 23:27
Nový
 
 
 
 
└ 
Re: OOP, dedicnost
Vít Šesták (v6ak) 22. 3. 2010 15:36
Nový
 
 
 
 
 
└ 
Re: OOP, dedicnost
Petr Krontorad 23. 3. 2010 09:27
Nový
 
 
 
 
 
 
└ 
Re: OOP, dedicnost
Vít Šesták (v6ak) 23. 3. 2010 16:45
Nový
Dekuji za velmi kvalitni clanek
hon2a 23. 8. 2010 11:57
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem