Přejít k navigační liště

Zdroják » JavaScript » Třídy, dědičnost a OOP v Javascriptu – I

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í.

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á).

Komentáře

Subscribe
Upozornit na
guest
148 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
gisat

léta působím jako javascriptový programátor a napsal jsem už mnoho článků o javascriptu a musím vám napsat, že jste to s tím vším nějak popletli.

Odjakživa funkce byla objektem, z funkce jde vytvářet další objekty, pomocí prototypové dědičnosti lze objekty rozšiřovat. Veškeré objekty vycházejí z objektu Object a z něj vycházejí další vlastnosti, které jsou všem objektům stejné.

Doporučil bych vám tímto pročíst si pár knih o OOP v Javascriptu, nebo si alespoň přečíst mé články na http://programovani.blog.zive.cz/category/javascript/

Mám tam spoustu článků o OOP v Javascriptu a také mimochodem pětidílný seriál o funkcích v Javascriptu.

Rozhodně za tři díly neopíšete celé OOP Javascriptu to ani náhodou. Tento článek je velmi nepovedený

peter

Som velmi rad, ze som nemusel to co pisete autorovi napisat ja, lebo osadenstvo zdrojaku by si zasa myslelo, ze kritizujem iba z principu.
Plne suhlasim. Clanok je popleteny a matuci. Autor zrejme moc nechape OOP ale najma Javascript ako jazyk.

Vsimli ste si, ze vsetci diskutujujuci, ktoru maju skutocne dobre IT vedomosti maju na zdrojaku auru okolo 10. :)

olin

O to bych si moc neříkal. Já je sem zatím nepsal, protože článek i přes to má svou informační hodnotu :-)

gisat

Danieli, odkaz na mé články o Javascriptu nejsou žádnou reklamou, pouze jsem Vás odkazoval na článek kde je proveden správný teoretický popis, i když to může vypadat namyšleně, já reklamu nepotřebuji, denně mi na blog chodí 150 až 700 návštěvníků. Také mé výtky neberte jako nějaké naparování či vychloubání se, tak to vůbec nemyslím.

Chcete abychom Vám řekli o nedostatcích ve Vašem článku, takže za prvé, píšete: „Funkce, to je prostá definice. Není přiřazena k žádné třídě, k žádnému objektu“,
že funkce jení objektem, je chyba, funkce je objektem, přebírá některé své „vrozené“ vlastnosti z objektu Object,tudíž je přiřezena k objektu Object v Javascriptu existuje dokonce objekt jako Function , z funkce tedy můžeme vytvářet objekty.

Objekty totiž můžeme vytvářet buďto tím, že vytvoříme funkci například takto:
function funkce(){}
a tímto zápisem se obracíme na konstruktor funkce var x=new funkce();
tečkovou syntaxí se pak můžeme obracet na jednotlivé proměnné funkce, objekt také můžeme vytvářet tak, že ho vytvoříme jako asociované pole. Ovšem vytvoření objektu jako asociované pole má svá omezení. Takový objekt můžeme nazývat literálním objektem.

Tudíž tvrdit, že objekt je v Javascriptu asociované pole je špané. Dříve se objekty opravdu vytvářeli jako asociovaná pole, dnes se dají vytvořit i z funkce a je to častější způsob vytvoření. Dále pokud vytvoříte objekt z asociovaného pole tak nemůžete vytvářet novou instanci pomocí slova new.

Dále píšete, nahoře, že funkce není objekt a dole zase že je.

Dále píšete o Closure, ale všude se closure říká uzávěry. Dále se ještě jednou vrátím k objektům. Dále když už hovoříte o objektech bylo by velmi vítané kdybyste řekl, že existují vestavěné objekty, a dále že objekty si můžeme vytvořit vlastní například z funkcí nebo jako asociované pole.

Celý popis funkce máte zmatečný, za prvé z funkce můžeme vytvářet objekt, funkce obsahuje proměnné a metody a můžeme ji nazývat třídou, na třídu se můžeme odkazovat konstruktorem pomocí slůvka new. Dále objekt window je globálním nejvyšším objektem vzhledem k DOM stromu dokumentu, nikoli k samotnému Javascriptu.

Dále uvedené názvosloví je velice špatné, psát jako o špatné funkci je opravdu špatný způsob, měl byste psát o uzávěrách. Dále píšete o modulech, ve skutečnosti jde o prázdný objekt, že kterého nejde vytvářet další instance takto se skutečně dají vytvářet statické objekty.

Opět jste špatně pochopil anonymní funkce. závorky před a za anonymní funkcí se dělají kvůli poli působnosti dané funkce, kvůli ničemu jinému se nedělají.

Dále pokud se nepletu je jQuery totéž co $, a navíc se tyto proměnné dají přepsat na vlastní označení.

Prostě celý článek je nepřehledný, nedůsledný, špatné názvy, špatně jste pochopil OOP v Javascriptu, jsou zde neúplné věci……

Dále, proč bych nemohl deklarovat metodu v konstruktoru, pokud chci tuto metodu ihned zavolat tak ji tam můžu volat, nemusím ji psát jinam. Dále co se týče for in tak to skutečně nepoužívám, je to tam uvedeno pouze jako možný způsob.

Aleš Roubíček

Zkuste si ten článek přečíst ještě jednou. Daniel zde za ‚funkci‘ označuje něco co je samostatná funkce nevázaná na žádný scope (vyjma globálního) a nevolá se jako ‚konstruktor‘. Jde pouze o vysvětlení použité terminologie a proč pro jednu věc používá několik názvů.

BTW Asociované pole != asociativní pole.

peter

Clanok je maximalne terminologicky paskvil. Nevhodny pre zaciatocnika, lebo mu nic neda a iba ho poletie. Daniel v clanku nevysvetlil ani ako funguje operator new (mozno to sam nevie) a uz tvori objekty ako divy.

Aleš Roubíček

OOP v JS není pro začátečníky a ani v článku nikde není nijak naznačeno, že je pro začátečníky určen.

Osobně netuším, jaké projekty za sebou mají IT odborníci peter a olin, ale Danovu práci znám a vím, že on jen málo lidí má takové znalosti JavaScriptu jako on. Tak si prosím od cesty nechce poznámky typu „možno ani nevie ako operator new funguje“.

pr.rybar

> Danovu práci znám a vím, že on jen málo lidí má takové znalosti JavaScriptu jako on.

Ak je toto pravda, optom sa asi dano nevie vyjadrovat primerane svojim vedomostiam. :(

gisat

Celé to tvrzení je mylné.

Podívejte se na následující:

function funkce(){}

document.write(ty­peof(funkce));
výsledek bude function

document.write(fun­kce.constructor);
výsledek bude Function() { [native code] }

Z tohoto jasně vyplývá, že funkce je objektem typu function, konstruktorem funkce je Function() a Function vyplývá z objektu Object.

Ovšem jiné je, když napíše, že funkci lze volat bez konstruktoru ale pokud vytvoří funkci z objektu Function tak lze funkci volat i konstruktorem.

Aichi

Pane, výrokem

Opět jste špatně pochopil anonymní funkce. závorky před a za anonymní funkcí se dělají kvůli poli působnosti dané funkce, kvůli ničemu jinému se nedělají.

jste vaší připomínku moc neozřejmil. Když vy můžete zkratkovitě soudit, budu i já. Pokud takto zmatkovitě píšete články, tak bůh s vašimi čtenáři.

O jaké závorky vlastně jde? :)

gisat

jde přesně o toto:

(functio(){
tělo funkce
})

ty kulaté závorky na začátku a na konci jsou zde kvůli poli působnosti

Aichi

Můžete mi to vysvětlit? Co je podle vás pole působnosti? Ve článku se mluví o scope, je scope to co myslíte? Není náhodou scope omezen složenými závorkami, které ohraničují tělo funkce?

gisat

Velmi rád vysvětlím.

Pole působnosti neboli anglicky Scope je trošku složitější téma než tady David nastínil.

Prakticky by se dalo říct, že pole působnosti je dáno ve funkci složenými závorkami. Pole působnosti také například řeší kdy daná funkce má přístup k proměnným další funkce.

Přístup k proměnným z jedné do druhé funkce mohou velmi krásně usnadnit uzávěry.

Nechci být opět podezříván z reklamy, ale o poli působnosti a uzávěrách si můžete přečíst v mém článku zde: http://programovani.blog.zive.cz/2009/07/rozsah-pusobnosti-v-javascriptu-a-uzavery/

Právě díky poli působnosti se doporučuje anonymní funkce uzavírat do kulatých závorek:
(function(){})

Aleš Roubíček

Ty kulaté závorky ale nemají s polem působnosti nic společného. Z anonymní funkce se zde vytvoří objekt, který se potom dalším párem závorek zavolá.

Michal Augustýn

Přesně tak, kulaté závorky na to nemají vliv.

Farrell

Chyba.

[code]var x = (function() {return ‚x‘;})();[/code]
žádný scope nevytvoří, jen předá návratovou hodnotu funkce obsaženou uvnitř, zde to je string ‚x‘

Jde to udělat 50ti způsoby jako třeba…
[code]
function foo() {return ‚x‘;}
var x = (foo)(); // x

var foo = function() {return ‚x‘;}
var x = (foo)(); // x

var x = ((((((function() {return ‚x‘;}))))()));
[/code]

pokaždé bude v proměnné x string ‚x‘, něco jiného je ovšem tohle:

[code]
function foo() {this.test = ‚x‘;return ‚x‘;}
var x = (new foo); // x

var foo = new function() {this.test = ‚x‘;return ‚x‘;}
var x = (foo); // x

var x = ((((((new function() {this.test = ‚x‘;return ‚x‘;}))))));
[/code]

kde žádný string nedostaneme, nýbrž objekt, v každém případě. Závorky tam jsou jen na okrasu, abys věděl, že tohle opravdu na scope nemá vliv.

jay

Mno, kouknul jsem se na vaše stránky a na nejnovější článek. Tedy rozhraní v jazyku, který nemá typovou kontrolu je opravdu užitečná, ale fakt užitečná věc :-)).
Jste si jistý, že víte o čem mluvíte?

gisat

Děkuji za kritiku :),

narozdíl od Daniela mám všechny články logické, vykládající v souvislosti. O všem co tady Daniel píče tak o tom mám také články. Skutečně jeho článek je matoucí, nic neříkající. Například ta etapa s moduly, to co tam nazývá moduly jsou prázdné objekty.

Pokud o tom nevíte, tak v Javascriptu se dají nasimulovat kroky a postupy OOP, které nejsou původně v Javascriptu vytvořeny. Jedním z nich jsou jmenné prostory které ve skutečnosti jmennými prostory nejsou. Rozhraní jsou možná v Javascriptu „šílenějším“ nápadem, ale i tak se používají, první díl celkem třídílného seriálu začíná od bezvýznamného vytvoření rozhraní z komentáře, kde kontrola není možná až po rozhraní kde kontrola možná je.

Ve svých článcích se snažím lidem otevřít nový náhled na Javascript.
Opravdu vím o čem píši mám za sebou ve světě internetu bohatou zkušenost v oboru Javascriptu.

Nikoho své články nenutím číst. Pokud se vám nelíbí tak je nečtěte.

jay

Nic ve zlém, ale mě Danielův článek přijde docela pochopitelný i když nějaké nepřesnosti v něm jsou. Díky „pružnosti“ javascriptu a tomu, že není skutečně OO je ovšem i terminologie kolem něho dost pružná. Např. modul a prázdný objekt mě přijde jako stejný termínový problém jako třeba funkce a metoda.
Ale k těm rozhraním, simulovat jmenné prostory v javascriptu má určitě smysl, protože pak omezím možnost konfliktů názvů, ale k čemu mě bude rozhraní?
I pokud naimplementuje vlastní kontrolu, jestli objekt odpovídá rozhraní, tak se chyba odhalí až při běhu scriptu. Takže je to ve skutečnosti test, který se spouští při každém spustění scriptu. To mě nepřijde moc efektvní. Testy se běžně dělají jenom po změnách v programu (vím že např. v článku zmiňovaný Douglas Crockford podobné postupy taky popisuje, ale o jejich užitečnosti mě zatím nepřesvědčil).
Ale možná mě něco uniká, mohl by jste prosím vás uvést odkaz na nějakou javascriptovou knihovnu nebo framwork, kde se rozhraní používá?

MD

Myslim ze resenim by bylo pouzivat jiny jazyk, ktery umi rozhrani (na rozdil od javascriptu) :-)

v6ak

Jo, třeba Javu díky GWT.

pr.rybar

Python?

MD

Ke třetímu odstavci. Opakujete pouze co sem psal. Mimochodem, kdybyste článek nečetl tak ledabyle, věděl byste, že pokud voláme funkci s operátorem new, nikdy ji nepíšeme s malým písmenem na začátku (viz váš příklad). Operátorem new totiž voláme funkci, která je konstruktorem, a konstruktory se píší vždy s velkým písmenem na začátku.

V popisu javascriptu, na ktery odkazujete na zacatku clanku, se mala pismena vesele uzivaji, viz https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Creating_New_Objects/Using_a_Constructor_Function

Aleš Roubíček

Zkrátka jde o konvenci ne o rys jazyka. :)

Michal Augustýn

Ano, je to tak – constructor function jedině s velkým písmenkem na začátku! ;-)

MD

No dobre, jde tedy ale jen o konvenci. Syntaxe je spravna i s malymi pismeny. Z vaseho popisu to vyznivalo tak, ze mala pismena jsou uplne spatne, error.

Aleš Roubíček

Porušování konvencí je mnohdy horší než error. Zatím co error se dá většinou dohledat a opravit, tak nedodržování konvencí je na přeshubu.

pk

Puvodni clanek mi prijde o dost srozumitelnejsi nez vase reakce :)

Aleš Roubíček

Ahoj Dane, pěkný článek, už se těším na další díly. Doufám, že to ostatním pomůže prorazit do JS stejně jako mně tvoje přednáška před lety. :)

Mám jen jednu výtku. Stále dokola opakuješ, že privátní/lokální členy nejdou testovat. Pokud budu považovat testování = jednotkové testování, pak je tato vlastnost zcela žádoucí. Testování privátních členů je test smell. :) Privátní členy netestujeme, protože jejich chování se může měnit – ostatně proto jsou privátní. Funkčnost privátních členů testujeme pomocí chování objektu navenek. Pokud je nedokážeme v testech veřejného rozhraní otestovat, pravděpodobně jde o zbytečné členy… :)

Michal Augustýn

Jojo, vidím to stejně :)

Aleš Roubíček

Ano, psal jsem před dvěma a půl lety. :) Navíc u metod vykoupej se a nauč se Gutha Jarkovského není žádný důvod ke skrývání, tyto mohou být klidně veřejně vystaveny a tudíž jdou snadno otestovat.

MD

Nevim, proc by mely byt verejne vystaveny, kdyz nemusi. Jen kvuli testovani? Zvlastni pristup…

Aleš Roubíček

Páč asi se nebudete mýt pouze v případě že budete balit ženu, že? Stejně tak platí i druhý případ. U těchto metod není žádný důvod je skrývat a s testováním to nemá nic splečného. On je to totiž nešťastně zvolení příklad. Zbal ženu by bylo lepší implementovat jako Command pattern s injektovanou strategií. ;)

Borek Bernard

To, že testy poněkud ovlivňují veřejné API, je běžné. Někdo to považuje za přirozené, někdo za špatné, ale změna API kvůli testům rozhodně není nic neobvyklého.

Michal Augustýn

Daniel jistě ví o čem píše, ale bohužel mi článek přijde trošku blbě strukturovaný :( Např. dva způsoby implementace tříd proložené povídáním o „modulech“.

Btw. kód:
var foo = function () {};
je opravdu neštastný, vzhledem k ladění. Tím se totiž vytváří anonymní funkce, která se přiřazuje do proměnné foo. Takže při ladění ve stack-trace uvidíte něco jako „anonymous_fun­ction125“ (záleží na konkrétní implementaci JS).
Troufnu si tvrdit, že je lepší funkce pojmenovávat, tedy psát:
var foo = function foo () {};

Ale Javascript je tak bohatý jazyk s rozmanitými možnosti, jak zapsat jednu věc, že IMHO nejde napsat článek o JS, na kterém by si někdo něco „špatného“ nenašel ;-) Kolikrát i záleží na kontextu, ve kterém autor JS uvažuje (použití v prohlížeči, na serveru, v databázi, …).

Nicméně se těším na další díly :) A přednášku na IDF :)

Tom5

Naprosto souhlasím s to nešťastnou strukturou.

A nechávat si rozuzlení třídy na další díl, je také nevhodné. Pokud jsou uvedeny špatné příklady, měl by být hned uveden ten správný.

Martin Malý

Víte… ono to rozuzlení zabíralo v celém textu (cca 45.000 znaků) dobrou třetinu. Přemýšleli jsme s autorem, že bychom ho – právě kvůli takovým komentářům – vydali celý v jednom kuse, ale tak dlouhý text většina čtenářů „neučte“. Jediná možnost, jak nechat „správný“ postup v jednom článku se „špatným“, bylo jejich společné vydání (30.000 znaků). Jakýmkoli způsobem bráno se text vždy logicky rozpadal na „jak se to dělá a dělat nemá“, „jak se to dělat má a proč“ a „jak se to dá udělat elegantně“. Nakonec jsme usoudili, že čtenář ví, co je to „seriál“, a chápe, že ačkoli je každý díl logicky uzavřen, bude něco řečeno až příště…

Karel

1. Seriál nemá být psán stylem „tady máte jeden díl, ale zatím ho nečtěte, protože bez toho dalšího v tom budete mít akorát bordel“. Tento díl v žádném případě není „logicky uzavřen“. Spíše než odbornou publikaci váš seriál zatím připomína mexickou telenovelu – tak dnes jsme se nic nedozvěděli, ale v příštím díle se už Esmeralda určitě vdá!

2. Buď jste měli oba (špatný i správný) postupy publikovat v jediném díle, nebo jste měli ten správný publikovat jako první. Psychologové už dávno vědí, že v člověku zůstávají hlavně první dojmy. Můžete do článku stokrát psát, že „takhle se to dělat nemá“, ale protože tu chybí jakékoliv srovnání (a jak se to tedy dělat má?), povedlo se vám v řadě lidí „zakotvit“ vámi uvedené „nesprávné“ postupy jako ty jediné správné (protože žádné jiné jste v článku neuvedl). To je síla podvědomí.

3. Javascript neumím a ani se ho neplánuji učit. Článek jsem četl jen proto, že mně zajímá, jak jsou jednotlivé metodiky (zde OOP) implementovány v různých jazycích. Nemohu proto posoudit obsahovou správnost článku, ale pouze formální. A po formální stránce je to tedy opravdu průšvih.

Ondřej Žára

Zde jen kratka noticka: uvedeny zapis „var A = function B() {}“ je principialne spravny napad, ovsem v Internet Exploreru (6–8) timto vzdy vznika v globalnim objektu vlastnost B, nezavisle na hodnote A.

Tedy, pokud treba pisu:

MujNamespace.Tri­da.prototype.Me­toda = function Trida_Metoda() {}

tak v IE bude najednou existovat window.Trida_Me­toda.

Ondřej Žára

Ano, máte pravdu, jedná se o aktuální scope. Nezávisle na tom však stále platí upozornění, že Internet Explorer (resp. JScript) se v tomto směru chová jinak, než ostatní implementace (nebál bych se dokonce použít termín „špatně“).

Nakonec jsem si dovolil lehce upravit kus vašeho kódu, linkovaný z příspěvku http://zdrojak.root.cz/clanky/oop-v-javascriptu-i/nazory/7955/ (vyhodnocování shora dolů) – moje verze viz http://jsfiddle.net/zsBLH/. Je vidět, že i pojmenovaná funkce není ve scopu viditelná až do doby své deklarace – to proto, že vznikla jako „function expression“ a ne jako „function declaration“. Hezké počtení o této problematice viz https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Functions#Function_constructor_vs._function_declaration_vs._function_expression nebo http://yura.thinkweb2.com/named-function-expressions/.

Michal Augustýn

Teď je správný čas použít mou větu Kolikrát i záleží na kontextu, ve kterém autor JS uvažuje (použití v prohlížeči, na serveru, v databázi, …).
Mé použití JavaScriptu je ale opravdu velmi speciální (vyžadovalo i nějaké hooky v samotné implementaci)…:D

Aleš Roubíček

MS AJAX to v debug verzi používá, je díky tomu přehlednější call stack při debugování. Jindy to opravdu význam nemá.

mizuki

ve vami uvedenem priklade ale pouzivate „function foo () {„, proto se to chova jinak. pri pouziti „var foo = function foo() {“ se chova samozrejme stejne jako „var foo = function() {„…

MD

Nelibi se mi, ze nahore pisete, ze vsechno je objekt (i funkce) a ma spolecneho predka Object. Nize pisete, ze funkce je prosta definice a ze neni prirazena k zadnemu objektu. Tak jak tomu mam rozumnet?

Ondřej Žára

„Neni prirazena k zadnemu objektu“ – tim autor mysli (alespon ja to tak chapu), ze funkce ve smyslu metody (tedy takova, ktera bude volana s teckou pred nazvem) neni svazana s tridou, u ktere je definovana.

Zatimco tedy v jinych jazycich piseme

class A { public method B() {} }

a je tak patrne, ze B „patri“ k A, tak v JavaScriptu zapis

A.prototype.B = function() {}

nevytvari zadnou logickou vazbu mezi (zcela normalni) funkci B a jeji (tridou) A. Uplne stejneho vysledku by bylo mozno docilit treba zapisem

var B = function() {}
A.prototype.B = B;

B je stale normalni funkce bez jakekoliv vazby na A.

Mazarik

Konecne sa objavil na zdrojaku po dlhom case clanok, ktory ma zaujal a prijemne prekvapil. S obsahom clanku suhlasim, aj ked si myslim, ze by to mohlo byt troska viac do hlbky, aby si pripadni programatori v js uvedomili, co sa ma pouzivat na co a ktore techniky su uplne nevhodne a preco. Js je totiz tak amorfny a ma tolko implementacii, ze zaciatocnici maju s jazykom velke problemy(tiez som ich mal a niektore dnes este mam:). Samozrejme by sa tym clanok predlzil a bol by asi nezazivnejsi a mohlo by to ludi odradit od citania.

fos4

Moc povedený článek, už se těším na pokračování.
Autora se chci zeptat jestli na konferenci internet developer forum bude obsah jeho přednášky stejný jako tento seriál. Díky

bzuK

Díky za článek, těším se na další díly.

logik

Steigerwald: Přestože ten článek někdy je trochu zmatený (což nekritizuju, protože z principu javaskriptu snad každej článek o něm musí bejt zmatenej), tak až na detaily i přijde velmi dobrý.

Hrebenar: Promiňte, ale většina vašich výtek je mimo, zřejmě jste článek poněkud nepochopil. Ale stejně smyslem Vašeho komentáře bylo získat více prokliků na Vašem blogu a ten zcela určitě splnil.

(abych byl adresnej, tak např. u modulu závorky kolem a za anonymní funkcí jsou nutný, protože je potřeba tu funkci zavolat – jako modul neslouží ta samotná anonymní funkce, ale právě tím voláním vytvořené closure společně s
vrácenou funkcí

Nebo že objekt není asociativní (nebo asociované :-D) pole? Ono snad v JS nejde napsat funkce[‚a‘]=? Co se mění na pravdivosti tvrzení: „každý objekt je asociativní pole,“ se mění tím, že se dnes většinou objekty vytvářejí ze speciálního asociativního pole, které lze ještě navíc zavolat?

Nebo ad jQuery – uvedené řešení je jednoduchá berlička pro to, aby kód fungoval i když jiná knihovna přepíše $ definovaný v jQuery. Opět jsou v příkladu všechny závorky nutné.

Shrnul bych to takto: Zatímco autor tohoto článku byť někdy malinko neobratně se snaží vysvětlit jak javascript funguje uvnitř a teprve z toho vyvozovat závěry, vy jste jaksi spoután svým poněkud omezeným viděním javascriptu a
hlubší porozumění zaměňujete za chybu…

danaketh

Pěkně jsem si početl. Těším se na další díl.

aprilchild

Pro ty, co to cetli 3× a stejne sotva pochopili – poslouchejte steidu (autor), jestli nekdo vi, o cem ve svem oboru mluvi, je to on. Tech par kritiku je typicka trolli zumpa, kterou se netreba zabyvat.

Martin Staněk

Nevěnuji se programování ecmascriptu zase tolik, ale v poslední době jsem se o možnosti OOP zajímal. Chtěl bych Vám nabídnout můj pohled na věc, co bych vlastně očekával od úvodního článku.

Psát pro širší publikum není snadné, ale stačí dodržovat některé základní postupy při psaní, které produkují lepší výsledky. Když se podívám na strukturu Vašeho článku, tak na první pohled vidím, že jste na ní příliš nepřemýšlel a psal jste, co vás napadlo. Je třeba začít osnovou a pak postupně formovat článek.

Především by na úvod neškodilo zmínit, co je vlastně míněno tím OOP v ecmascriptu se srovnáním, jak je to vnímáno jinde (rozhodně najdeme rozdíly v chápání OOP v ecmascriptu a smalltalku). Jeden odstavec by si to zasloužilo.

Rozhodně bych se vyvaroval nějakému přehledu pojmů, myslím si, že je vhodné vysvětlit pojem ve chvíli, kdy je potřeba a s krátkým příkladem. (Ty tam sice obvykle máte, ale docela by mě zajímala statistika kolik lidí na ně opravdu kliklo)

Celkově ten článek působí neuceleně, psaný horkou jehlou, což je zřejmé i z povahy diskuze, kdy jsou zpochybňovány Vaše znalosti. Také nesprávně.

Doufám, že si do příštích dílů z diskuze něco odnesete. Toto téma mě velice zajímá a rád bych se o OOP v JS dozvěděl, co nejvíce.

aprilchild

Nic ve zlem, ale nebylo by jednodussi priznat si, ze mi dela potize napoprve pochopit psany text? A v case usetrenem psanim zbytecneho komentare zkusit precist pecliveji jeste jednou? :)

Dan uz z povahy veci nepise pro siroke publikum, tema neni jednoduche, pokud vas to zajima – v klidu ctete a studujte, a na komentovani alespon na chvili zapomente.

Ano, i muj prispevek je zcela zbytecny.. :)

Martin Staněk

Je vtipné, že mi vnucujete studium, když vůbec netušíte, jaké znalosti mám nebo nemám. Nevím čím jsem podle vás dal najevo, že bych článek nepochopil. Můj komentář nabídl pohled na formu článku pro autora. Dobře napsaný článek na téma OOP v Javascriptu si představuji jinak.

Pokud Dan nepíše pro široké publikum, tak by neměla téměř celá první polovina článku obsahovat naprosté základy jako co je to objekt, kontext nebo scope. Pokud to čtenář neví, tak nemá smysl, aby ten článek vůbec četl. Je třeba přemýšlet nad tím koho chci oslovit.

Souhlasím s vámi, váš příspěvek je zbytečný ;)

Aleš Roubíček

Jenže začátek článku není vysvětlení základů, ale definice použité terminologie. Je vidět, že jste to, stejně jako většina diskutujících tady, ještě nepochopil. Což je smutné.

karmi

> když vůbec netušíte, jaké znalosti mám nebo nemám.

No, možná, že jste s tím po zdejším obyčeji začal sám a docela zhurta:

>> Když se podívám na strukturu Vašeho článku, tak na první pohled vidím,
>> že jste na ní příliš nepřemýšlel a psal jste, co vás napadlo.

WTF? Tady na Zdrojáku se s železnou pravidelností vyskytují jasnovidci. Autor „psal, co ho napadlo“…

>> Především by na úvod neškodilo zmínit, co je vlastně míněno tím OOP (…)

Ale. To je docela laciná „kritika“, ne? (Ta debata s pány gisat, peter, atd o něco výše, to není kritika, ale komika. Taková řekněme „krampolovská“.) To bychom si taky mohli začít vykládat že JavaScript se původně jmenoval _Mocha_ atd atd atd.

>> (…) vyvaroval nějakému přehledu pojmů (…)

Z kontextu článku je ale zjevné, že _právě_ přehled pojmů na začátek je potřeba, včetně vysvětlení, proč je dle autora lepší anglické pojmy _nepřekládat_ do češtiny. Neboť většina žabomyších hádek okolo JS u nás se zamotá už v tom, že _scope_ nazývá každý nějak jinak a především tomu vlastně na 100% nerozumí, ale rozumí tomu jen trošičku a o tu trošičku se taky bude hádat.

Článek je vynikající. Těším se na další díly. Je nesmírně osvěžující přečíst si něco a přímo fyzicky v tom _vidět_ to porozumění věci. To se stává zřídka.

(Už jsem třikrát smazal nějakou reakci na místní jasnovidce a kritiky, tak tentokrát již odešlu. Aby to nevypadalo, že to tady čtou jenom mašíblové.)

Martin Staněk

To je celkem škoda, protože ten titulek vystihuje téma mnohem lépe a taky by nedošlo k některým nedorozuměním. Až bude celý seriál venku, tak určitě bude působit kompaktněji. Díky

Martin Malý

Hele, ještě že čteš ty náhledy, co? :)

s

Jsem ohromen. Tohle nepamatuju, nemam horkost? Teplota v analu… 36.6? V norme. Rooote! Nezblaznil ses? Zrak ok, alkohol v krvi v norme… Kurwa, ja ten clanek precet az do konce. Chapete to? Ja to precet az _DO_KONCE_ Hrabu se, hrabu, hrabu, hrabu… Kde se asi muzu hrabat? V pameti se hramu. A nejak se nemuzu dohrabat. Kdy se vam naposled stalo, ze byste tu neco docetli az do konce?

Dane, chvalit te nebudu, protoze bys spychnul a pokracovani uz bych pak treba nedocet. Kazdopadne, mas me simpatie. :-)

Michal Augustýn

A já přečetl tenhle názor až do konce, protože jsem byl zvědavý, jaké bude rozuzlení :D

pr.rybar

To myslite ironicky, alebo vazne? :)
Dufam ze ironicky. Ak vazne, volajte si 112.

s

chapu ze z me reakce nemuselo byt uplne jasne, jestli se mi clanek libil nebo ne. Takze, to shrnu, libil :-)

pr.rybar

A volali ste? :)

s

rval sem to jak na lesy, stoooooodvana­aaaaaaaaact… a nic :-)

pr.rybar

To je jasna diagnoza. :)

Rene

Javascript aktivně nepoužívám, rád ho nemám, ale přesto jsem článek přečetl jedním dechem :).
Takže Dane, jako prostý laik ti děkuju za článek, odborníci na JS ti v komentářích určitě ještě každou větu rozcupují, aby se jim lépe spalo.

Blízkost hnoje přitahuje masařky, blízkost Rootu evidentně hovada.

Dříve platilo, že co Čech, to muzikant. Dnes, co Čech, to evidentně expert na javascript. A všichni JS experti si dnes dali sraz na Zdrojáku.:)

v6ak

Pokud se vykašlu na privátnost, pak může nastat problém u potomků, které přeci nemusí zajímat, jaké mám privátní vlastnosti a metody, ne?

Samozřejmě, v případě preference kompozice před dědičností (správně) to je většinou OK, ale chtěl jsem ukázat, že privátní viditelnost má smysl nejen co do dokumentace.

OT: Dál bych byl v seriálu rád za nějakou budoucí zmínku o volání parent konstruktoru.

v6ak

Já reagoval na „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ů.“.

BTW: Poslední způsob vytváření třídy taky není zrovna chválen, ale věta „Ukážeme si dvě falešné a jednu správnou.“ napovídá, že by to mohl být ten správný. Asi by to chtělo trošku korekci srozumitelnosti. Já vím, asi to bylo myšleno tak, že to není správný způsob, ale vznikají při něm skutečné třídy.

v6ak

To je celkem jasný. Já ze článku pochopil (nečetl jsem úplně důkladně, něco znám), že správný způsob budou asi ta podtržítka. A na to byla ta moje reakce.

Jinak za informace o parent constructor call děkuju předem.

Michal Augustýn

Pokud se nemůžete dočkat, můžete mrknout na můj článek, kde volání konstruktoru parenta používám ;-)

Michal Augustýn

Já vím ;-) Některé jsem si uvědomil s odstupem času, ještě dřív, než jsi začal rýt ;-)
Review, resp. přepis bez chyb, jsem právě plánoval tady na Zdrojáku, ale teď mám obavu, že mi to nepovolí, aby tu nebylo přejavascriptováno… Tak asi radši napíšu něco o ASP.NET MVC :o) Ať Ti nelezu do zelí :)

junix

No, prave pasaz o dedicnosti je v tvem jinak dobrem clanku slabinou. Tvrzeni, ze dedicnost v JavaScriptu neexistuje je jadrem problemu. Za takoveho predpokladu by byl i tvuj zpusob volani konstruktoru predka dobrym zpusobem, jak si dedicnost doplnit.

Jenze Javascript dedicnost primo podporuje. Tu prototypickou. O ni a o problemech, ktere nam prinasi – prototyp vs. inicializace instance – bude pocitam pristi dil, takze bych uz v tomto tematu dale nepredbihal :)

Aichi

A nebo můžete používat knihovnu JAK a používat dědění a volání metod předka jak je vám libo :) http://jak.seznam.cz

David

Souhlasím s Martinem Staňkem, že by si článek zasloužil lepší strukturu. V žádném případě nechci zpochybňovat znalosti autora o JavaScriptu (je vidět, že je má), ale stylisticky působí článek trochu zmatečně. Vedle toho bych chtěl poukázat na větu:

„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.“

Nevím kde autor bere tolik sebevědomí, že kritizuje Douglase Crockforda, senior JavaScript architekta firmy Yahoo! a člena komise, která určuje vývoj jazyka JavaScript, za jeho články. Nechci být hrubý, ale možná by si měl autor sednout na prdel a zamyslet se nad vlastními články.

David

Děkuji za odpověď. Články, které uvádíte, jsem četl, a i přesto, že Crockfordovi původní techniky se v moderních frameworcích už nepoužívají, stále mají články s jejich popisem velkou informační hodnotu a v žádném případě bych je nepovažoval za „nepovedené“. Naopak v nich lze vyčíst postupný rozvoj programovacích technik používaných v JavaScriptu.

V každém případě rád vidím články o JavaScriptu na Rootu a těším se na pokračování seriálu.

Bauglir

Pamatuju ještě černý Root, ale na takhle špatný si nemohu vzpomenout

1/ JS samozřejmě třídy nemá, citovat wiki a ještě takovou hloupost je úsměvné, to je definice pro někoho, kdo nikdy o OOP neslyšel. Programátor musí vědět, co to znamená „třídní programování“: zapouzdření, dědičnost a polymorfismus, přičemž JS poslední 2 vlastnosti neobsahuje. To, že se dají obejít (rozšiřováním předpisů, přiřazování prototypů) ještě neznamená, že má třídy. JS má typy, má objekty a nikdy nemělo třidy. Když už píšete články pro programátory, citujte alespoň z trochu relevantních zdrojů, jako například specifikace ECMA (http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf), strana 3: ECMAScript does not use classes.
To, čím se JS tolik liší od ostatních jazyků je právě neexistence tříd, ale existence prototypů. Neexistují klasické třídy a neklasické třidy.
Pojem tříd a instancí nemá v článku žádný význam, pokud to někdo chce číst v souladu s realitou a správně, čtěte typy a objekty.
Věty jako „Falešné, protože ve skutečnosti nejde o vytváření instancí tříd, ale o konstrukci podobných objektů.“ jsou potom už jenom vtipem.

2/ JS nemá nic takového, jako primitivní typy, to, že mžete napsat
var num = 5;
je jenom deklarací objektu typu Number jeho literálem, pokud by se jednalo o primitivní typ, následující konstrukce by nebyla možná:

var a = {'num': 5};
alert(a.num.toString());

věřte, že funguje skvěle

3/ Následně se článek bohužel už věnuje „třídám“ a „instancím“ a z tohoto hlediska ho nemá smysl číst.

Bez ohledu na to, jak dobrý je pan Steigerwald programátor, tak jeho způsob prezentace a vysvětlování JS je strašný a dělá JS medvědí službu. Každý, kdo se kdy setkal s třídami v OOP se musí při seznamování s JS dozvědět hned na začátku jednu věc: JS třídy nemá, zapomeň na OOP tak, jak ho znáš z jiných jazyků. JS má prototypy a ty nemají s třídami nic společného.

David Grudl

Špatný komentář, ale zdaleka ne nejhloupější zde :-)

ad 1) pokud je definicí třídního programování zapouzdřenost, dědičnost a polymorfismus, znamená to, že např. Python, který nemá zapouzdření členů tříd, není „třídním“ jazykem? To by bylo hodně odvážné tvrzení, co?

ad 2) budete velmi překvapen, ale typeof num nevypíše Number :-) (na velikosti záleží). Dokonce si můžete vyzkoušet, že čísla jakožto primitivní typy se do funkcí nepředávají referencí, narozdíl od objektů. Atd.

pr.rybar

Špatný komentář, ale zdaleka ne nejhloupější zde :-)

1) Medzi jazykmi Python a Javascript je dooost velky rozdiel co sa tyka tried. Python triedy ma a Javascript nie.

koroptev

dle meho intuitivniho citeni, ktere ma asi tak stejnou vahu jako vase neduvera v odvahu vami nastineneho potencialniho tvrzeni, je jazyk bez zapouzdreni (ale s dedicnosti a plymorfismem at uz to znamena cokoli) vice tridni nez jazyk bez dedicnosti..

jinak si tez myslim, ze tridni jazyk je ten, jehoz OOP je zalozeny na tridach, coz JS neni

a kamenujte me

peter

Neviem ake su Vase znalosti jazykov Python a Javascript, ale skutocne Javascript triedy na rozdiel od Pythonu nema. Kde ste videli triedy v Javascripte?

xx

> Je častou chybou programátorů začátečníků, brát všechny pojmy dogmaticky.

Problém je v tom, že když nepoužíváte přesné a jasné definice základních pojmů, tak se pak vlastně neví, o čem mluvíte. Odstrašujícím příkladem může být pojem OOP. Když někomu řeknete, že jazyk XYZ podporuje OOP, tak je to jako byste nic neřekl (možná říkáte, že jazyk podporuje dynamic dispatch, ale to je asi tak všechno).

pr.rybar

Aj ja som za striktne definovanie a dodrziavanie pojmov. Je to znak profesionality.
Kto sa nevie vyjadrovat, nech nepise clanky, lebo narobi viac skody ako osohu.

Jakub Nešetřil

A já ne. Dogmatické a striktní chápání jakéhokoliv pojmu vidím jako programátorovu slabinu a jeho neschopnost. Místo chápání konceptů se brání definicemi pojmů.

Dobrý programátor je schopný používat koncepty a dokonce o nich i komunikovat s ostatními bez takovéhleho dogmatismu.

Dan Steigerwald je jeden z nejlepších JS programátorů v Čechách a článek který napsal čouhá nad českým průměrem znatelně. Možná snad jen to je jeho chybou – tedy že je článek určený inteligentním, uvažujícím lidem.

pr.rybar

> Dogmatické a striktní chápání jakéhokoliv pojmu vidím jako programátorovu slabinu a jeho neschopnost. Místo chápání konceptů se brání definicemi pojmů.

Ako mozete chapat koncept, ked nechapete pojmy?

> Dobrý programátor je schopný používat koncepty a dokonce o nich i komunikovat s ostatními bez takovéhleho dogmatismu.

Mam pocit ze Vy asi inak chapete aj moju vetu „striktne definovanie a dodrziavanie pojmov“. To potom ale vedie na styl diskusie „Ja o voze, ty o koze“, co je presne teraz nas pripad.

Bauglir

Dogmatické chápání pojmů je základem, protože (teď nemluvím o panu Steigerwaldovi, dávám obecné příklady) když si někdo bude plést proměnnou a typ, funkci a metodu, hodnotu proměnné a pointer na proměnnou, a já nevím, co ještě, tak to není dobře. Uvědomte si, že toto všechno nejsou jen tak pojmy něčeho abstraktního, ale naprosto konkrétní koncepty, které pokud zaměníte v kódu, nastane průšvih. Navíc se tu nebavíme o nějakém klábosení ajťáků večer u piva, ale o naučném článku, který by měl být maximálně přesný, protože jinak mate.

Nejde o konceptuální dogmatizmus, fakt, jestli tomu říkáme, nebo neříkáme třída nemá nic společného s tím, jestli jsou třídy oblíbené, používané, dobře používané… Nikdo se tu nehádá o tom, jestli je prototypování lepší, než třídy, nebo ne.

Prohlášení o tom, že někdo, kdo je schopný programátor + má publikační činnost patří k jedněm z nejlepších programátorů mě vždy rozesměje. Teď se nechci pana Steigerwalda dotknout osobně, tato výtka se ho netýká, ale pane Nešetřile, znáte VŠECHNY programátory v Čechách, abyste mohl takhle hodnotit? Navíc od kdy se dobrý programátor = dobrý publicista?

Neinteligentní Neuvažující Člověk

xx

> Místo chápání konceptů se brání definicemi pojmů.

Tady nikdo neříká, že to má být na úkor chápání konceptů.

Koncepty se hodí, když o problému přemýšlíte v „obecné rovině“. Ale až vymyslíte, jak se problém dá vyřešit, je potřeba ověřit, že váš postup je správný. A zde už si s koncepty nevystačíte. Zde už potřebujete zadefinovat problém, popsat algoritmus na jeho řešení a dokázat, že řeší definovaný problém.

Aleš Roubíček

Jak souvisí algoritmizace kokrétně s JavaScriptem? V JS jde hlavně o reaktivní proces…

V JS jsou platné především koncepty.

xx

To měl být jen příklad na to, že s koncepty nevystačíte.

koroptev

tohle je docela zajimave, co jste nevedomky zminil – algoritmus – tenhle clanek byl o vsem jinem nez o algoritmech, a prijde mi to symptomaticke, zel i pro me vlastni zamestnani ..

Bauglir

Děkuji za reklamu, jsem to já :)

ad 1/ ano, specifikace mluví o třídách asi na 5 místech… všude, kde vysvětluje, v čem se JS liší od třídních jazyků.

ad 2/ konsenzus je dohodou/porozuměním mezi lidmi, na faktech ale obvykle nic nemění :). Můžete si tomu říkat třeba druh ovoce ale ovocem se to nestane. JS prostě nemá třídy :)
Fakt, že tomu Vy a další budete říkat třídy vede jenom k tomu, že se programátoři, kteří k JS přijdou z jazyků, které podporují třídy, budou snažit opakovat stejné postupy, na které jsou zvyklí a oni prostě v JS nepůjdou… Když to řeknu jinak, pokud budu přecházet mezi ObjectPascalem, PHPkem a C#, změním spoustu věcí, syntaxi, knihovny, frameworky… ale nezměním paradigma pro vytváření objektů. Pokud se ale dostanu k JS, tak třídní paradigma musím zahodit a musím začít přemýšlet v prototypech.

ad 3/ nemám problém přiznat, že s primitivními typy jsem se sekl. Nicméně i Vy máte Vašem rozsáhlém popisu chybu:
„Převést primitivní hodnotu na její objektovou reprezentaci, lze pomocí přímého volání konstruktoru, ani nemusíme použít new.“
Samozřejmě musíte, zkuste si pro změnu i Vy nějaké příklady


var a = Number(2);
var b = new Number(5);
a.data = 5;
b.data = 5;
alert(a.data + "n" + b.data + "n" + (typeof a) + "n" + (typeof b));

i specifikace jasně píše: „The Number Constructor Called as a Function: When Number is called as a function rather than as a constructor, it performs a type conversion. Number ( [ value ] ):
Returns a Number value (not a Number object) computed by ToNumber(value) if value was supplied, else returns +0.“

4/ nebojte se, já si to pročetl a pročtu si i další díly, některé věci, které jsem ani nekomentoval, protože předpokládám, že budu mít možnost v jiných částech

olin

Naprosto souhlasím (jsem také čtenářem ECMA-262). Uvidíme ale až v pokračování seriálu, jestli detailní vnímání specifikace a přesné chápání pojmů bude mít vliv na pochopení souvislostí, protože i nesrovnalosti v pojmech se často řeší dobře zvolenými příklady. A nakonec se stejně lidé vracejí k příkladům, než k textu. Učebnice z tohohle seriálu prostě nebude, informační hodnotu ale mít bude.

MD

Nechci vypadat jako hnidopich, ale z tehle obsahle diskuse mam cim dal vic pocit, ze javascript je velmi nepovedeny jazyk. Proc se musi objevovat techniky jak udelat tohle a jak tamto, misto toho, aby to bylo zakotveno primo ve specifikaci jazyka? Prijde mi to stejne spatne jako zakony – potrebujete k nim pravni vyklad, abyste vubec vedeli, co se tim zakonem vlastne chtelo rict.

Nejsem zadny odbornik, ale treba actionscript mi prijde jako mnohem povedenejsi scriptovaci jazyk (klicova slova jako package, class, extends napovi…)

Ondřej Žára

Možná bych nahradil přívlastek „nepovedený“ za „komplexní“ či „složitý“. S dodatkem, že na první pohled vypadá jednoduše, ale zdání klame.

Zakotvení některých principů ve specifikaci by situaci jistě svým způsobem usměrenilo, jenže právě nesmírná flexibilita a expresivnost jazyka je jeho hlavním atributem.

Lehce negativním důsledkem pak je, že jedna „technika“ (v tomto případě OOP) je v praxi realizovatelná několika různými způsoby. Jejich přednosti, ale hlavně nevýhody, pak (doufám) jsou/budou zmíněny v této i dalších kapitolách článku.

Rozumný čtenář si stejně nakonec vybere sám – za předpokladu, že korektně pochopí všechny principy, bude jeho volba jistě správná.

pr.rybar

Komplexnost a zlozitost jazyka je zial v pripade Javascriptu a jeho nasadenia dost nevhodna.
Techniky riesenia mennych priestorov a dedenia su problematicke.
Myslim, ze napriklad Python by bol ako potencialna nahrada Javascriptu omnoho produktivnejsia a vhodnejsia pre beznych programatorov.

koroptev

tohle se urcite nebude libit – protoze mozna urceni, duvod existence, ucel JS byl puvodne byt skriptovacim embedded jazykem a to embedded zejmena uvnitr nejakych jiz existujicich datovych struktur (prohlizec – DOM), proto ten duraz na lehkou modifikaci prostredi (prototypovy objektovy system, moznost prilepit si cokoli kamkoli) a mensi na vytvareni rozsahlych veci od nuly (vypusteni modulu, ne tridy)

a k tomu ucelu ho ohybat potreba asi nijak zvlast neni/nebyla

no ale lidi delaj vsechno a kdyz tam jsou plne closures, pak lze i toto

jelikoz se doba posunula a ten ucel se asi trochu posunul, tak ted dle Wikipedie ( http://en.wikipedia.org/wiki/ECMAScript#Features_2 ) jsou asi i ty tridy na poradu dne..

koroptev

1.) javascript (soucasna verzi) je hodne jednoduchy a minimalisticky jazyk, moc konceptu tam neni, proc do nej zavadet pojem „trida“, kdyz OOP system, ktery pouziva, je tzv. prototypovy a „klasicka“ OOP (dejme tomu C++ cesta) terminologie zde nedava smysl?
2.) scope je velmi jednoduchy koncept, nevynalezl ho javascript a neni na nem nic sloziteho, priklad s mercedesem v garazi se ztmavenymi okny je naproste psycho, asi jako zmrvit vtip a divat se na taktni utrpne usmevy lidi kolem
3.) closure neni jiny nazev pro scope, tak jak to chapu, je to vec implementace scope, scope rozhodne maji i jazyky, ktere closury s tou funkcionalitou, na kterou jsme zvykli z funkcionalnich jazyku, neimplementuji
4.) „V Javascriptu platí, že vše co není primitivní typ je asociativní pole, krátce objekt. Funkce je objekt..“ → vyplyva z toho, ze funkce je asociativni pole? a je?

zbytek jsem necetl, kecy nectu

David Grudl

ad 1) pojem třída už zaveden je a cílem článku je ho vysvětlit. Zkuste spíš zvážit, jestli je C++ skutečně ono „klasické OOP“, nebo spíš jestli neexistuje OOP v podání C++ stejně jako OOP v podání JavaScriptu. C++ je poměrně mladý jazyk, batole proti OOP.

ad 2) scope JavaScript nevynalezl. Kdo to tvrdí? Proč to vyvracíte?

ad 4)

var funkce = function() {
    alert('ahoj');
}

funkce.a = 1;
funkce.b = 2;

alert(funkce.b); // vypise 2

Ehle, je to tak, funkce je asociativní pole. Mýlil jste se, takže článek by pro vás byl velmi užitečný.

koroptev

1.) C++ (popr. jazyky, ze kterych vychazi jeho OOP – a jejich terminologie) je starsi nez JS, „popularizoval“ li se v souvislosti s tim C++ nejaky pojem (trida napr.), je trochu hloupe, kdyz ho nekdo pozdeji ohyba, muj nazor
2.) narazel jsem na velmi neobratne vysvetleni, na tu nepruhlednou omacku + nektere komentare, ktere z toho delaji neco, co to neni, kdybych napsal „vysvetlovanim toho, co to je scope, objevujete kolo (v pripade, ze to delate neobratne za pomoci mercedesu) a nosite drivi do lesa“ bylo by to srozumitelnejsi“? Konkretne k te posledni otazce (vyvraceni) – protoze chci, prekvapive, vim, zvykejte si.
4.) nevedel jsem to, pripoustim, ze jsem spis predpokladal opak, ale proto jsem se ptal, abych se to dozvedel; ne ze by to menilo neco na tom, jakym zpusobem JS (nebo funkce v JS) pouzivam (nebo spis nepouzivam, ackoli se mi libi – kvuli neexistujici nativni implementace s nejakou relevantni mnozinou knihoven – neco jako Jscript.NET, pro ktery jsem ovsem nenalezl nejake podpurne nastroje)

muj hlavni dojem – mel-li to byt clanek o tom, kterak implementovat tridni objektovy system pomoci closures, pak to stacilo napsat, neni v tom vubec nic JS specifickeho, cili se dala vypustit cela ta omacka, mateni (pod pojmem OOP v JS si clovek asi predstavi neco jineho) a neumele vysvetlovani pojmu..

olin

ad 4) Neboj se. Tvrzení, že funkce či objekt je asociativní pole, vystihuje sice na první pohled podstatu, není to ale vůbec přesné. Asociativní pole je totiž pouze datová reprezentace, zatímco objekt a funkce jsou složitější pojmy. Zůstanu proto jen u objektu, což je v JS množina vlastností (hodnot, prototypu, funkcí, konstruktorů…) – slovy OOP by se dalo říct, že obsahuje atributy a metody.

Říkat, že objekt je asociativní pole, je hodně zjednodušující (i když pro mnohé začátečníky dostačující).

Např. pro datový typ Array – navzdory tomu, že to je Object – to třeba neplatí, protože operace přiřazení (x[4]=5) nepřiřazuje pouze ke klíči 4 hodnotu 5, ale zároveň upravuje vlastnost (atribut) length.

Jiný příklad nalezneme hned u další vlastnosti JS – prototypové dědičnosti. Zde také naráží myšlenka asociativního pole, protože se při nenalezení klíče v dané instanci hledá v objektu schovaném pod klíčem prototype (pak případně i v jeho prototype a tak dále, dokud už další prototype neexistuje).

Na objekty tedy lze s jistou dávkou zjednodušení pohlížet jako na asociativní pole, je to ale velmi chytré (až vyčůrané) asociativní pole :-)

Tenhle článek obsahuje spoustu takových nepřesností. Nu což, někomu to prostě vadí, někomu ne. Já si myslím, že až bude článek kompletní, tak si v něm každý něco najde. Ten, komu vadí pletení pojmů, se může od pojmů odtrhnout a odnést si jádro věci. No a ostatní se na pojmy zas tak nekoukají, takže si odnesou to samé :-)

pr.rybar

> ad 1) pojem třída už zaveden je a cílem článku je ho vysvětlit.

Prosim mohli by ste nam predviest ako zapiseme triedu v Javaskripte? Myslim skutocnu triedu/typ a nie prototyp objektu.

koroptev

to samozrejme nejde; tridni OOP lze zavest pomoci closures, jak je ukazano v clanku, coz je o dost pohodlnejsi, nez simulovat OOP v C, coz ale rovnez lze a rovnez to z C nedela objektovy jazyk alespon dle dnesnich obvyklych standardu vnimani tohoto terminu

peter

Kedze neexistuje trieda, nie je ziadne „triedne“. Javascript ma prototypy. Je to prototypovaci objektovy jazyk a nie triedny. Ci si Vy osobne, alebo autor clanku zavediete nejaky pojem a budete ho pouzivat na veci nic nemeni.

peter

Ziadna definuicia triedy pre Javascript neexistuje!
Specifikacia Javascriptu ten pojem nepozna a je zbytocne sa o triedach v kontexte Javascriptu ako jazyka bavit.
Chapete? Asi nie. :(

vid. bod 1 v http://zdrojak.root.cz/clanky/oop-v-javascriptu-i/nazory/8009/

Michal Augustýn

Nesouhlasím. Specifikace JavaScriptu sice pojem třída nezná, ale proč bychom si ho nemohli zavést? Pojem „třída“ pro JavaScript bych přirovnal v návrhovému vzoru.
Jestli má tento „návrhový vzor“ v případě JavaScriptu smysl a je dobré ho používat, to je věc na další diskuzi…

peter

Skuste napisat clanok o 3D grafike a namiesto „vertex“ pouzivat slovo „point“, namiesto „edge“ pouzivat slovo „line“ a namiesto „face“ pouzivat slovo „plane“. Asi vas za odbornika povazovat nebudu hoci ste uz co to v 3D naprogramoval.

Pojem „trieda“ je vseobecne znamy, definovany a zauzivany v jazykoch ktore triedy maju. Pretazovat pojem „trieda“ len preto, ze autor clanku nema v slovniku dost slov je nevhodne a nehodne skutocneho odbornika.
Alebo sa chcete vy, alebo autor clanku, preslavit ako vynalezca tired v jazyku, ktory triedy nema?
Ako vidite vasa originalna trminologia vyvolava iba nepokoj a vlnu nedorozumeni v diskusii.

Hovori sa: „Ak pomenujete v jazyku C parametre funkcie main inak ako argc a argv je to urazka vsetkych skutocne dobrych programatorov v jazyku C.“
Hovorit o triedach v Javascripte je nieco podobne. :(

paranoiq

Dane, nejsem žádný OOP expert. mé objektové vzdělání je omezeno pouze na C++, PHP, Python a Javu. pokud ale z těchto čtyř vyvodím nějakou definici třídy (a nechtěj prosím abych ji psal), dojdu k závěru, že JS třídy nemá (někde uvnitř hlavy mám dvě množiny „třídní OOP“ a „prototypové OOP“. nemají průnik)

pozor, to nám ale nijak nebrání třídy v JS používat! :P

když jsem kdysi poprvé zkoumal možnosti třídního OOP v JS narazij jsem na myšlenku, že třídní vlastnosti mohou být pomocí jiných prvků jazyka ‚emulovány‘. s takovou definicí jsem osobně naprosto spokojený

velice ti děkuji za článek a těším se na příští

belzebub

Mozna je na case naucit se nejaky JINY jazyk :)

Vase argumentace je podobna tvrzeni: „Jezdil jsem uz ve Felicii, ve Fabii i v Oktavce, a vsechny mely masku chladice v podobe svislych mrizek. Proto musi byt maska chladice vzdy ze svislych mrizek“.

Michal Augustýn

Ale tady to asi někdo vůbec nepochopil! Šup šup, přečíst můj „názor“ ještě jednou ;-)
Já neříkám, že by se mělo místo zavedených pojmů používat něco jiného. Já říkám, že může být vhodné zavést označení pro nějakou typickou konstrukci, de facto tedy pojmenovat návrhový vzor.

V některých jazycích prostě třídy jsou v základní syntaxi (např. C#), v některých ne (např. JavaScript) a tudíž může být vhodné si to tam nějak dobastlit.

Je to podobné, jako by tu byl třeba článek „Implementace singletonu v C#“ a Vy jste tu vykřikoval, že ve specifikaci C# žádný singleton není a tudíž je úlná blbost o něčem takovém psát, že to přináší jen zmatení a že přece hlavní metoda programu by se měla jmenovat Main.

Btw. jestli jste mě chtěl oslnit svými znalostmi z počítačové grafiky, bohužel Vás musím zklamat. Vývoji herních, potažmo grafických enginů, jsem se věnoval intenzivně několik let, obhájil jsem na podobné téma diplomovou práci a i si střihnul nějakou tu přednášku na konferenci pro herní vývojáře ;-)

junix

Podlehl jsem stejnemu pocitu, jako vetsina diskutujicich, ze vsemu rozumim nejvice :) a mam potrebu se vyjadrit jak k clanku, tak k diskusi.

1. K diskusi – vede se tu plamenna debata o tom, jestli ma javascript tridy, o nejakem „klasickem OOP“ a „prototypickem OOP“ a ze jedno ma polymorfismus a druhe ne a podobne nesmysly.

OOP je jedno. Jedna se o obecny pristup, ne o konkretni podobu v nejakem jazyce. Vychazi predevsim ze dvou veci: objektu a jejich chovani – polymorfismu. Nic vic.
Pak jsou tu dva sekundarni principy – zapouzdreni, a dedicnost.
U dedicnosti vidime rozdily, ktere tu zatim nikdo spravne nepojmenoval.

Mame tu tridne-instancni dedicnost (C++, Java, Ruby, Python, SmallTalk, CLISP atd.), kde je dedicnost staticka, definovana mezi tridami. Objekty jsou pouze instance. To je mimochodem princip velmi vzdaleny realite, ale jednoduseji realizovatelny.

Druhy typ je dedicnost prototypicka (self, IO), ktera je dana primo vztahy mezi objekty. Objekt A je potomek objektu B, protoze B je jeho prototyp. To je urcite neco blizsiho realite.

Ano, dedime nektere rysy lidskeho druhu, ktery je zdedil z opice (tridne-instancni pripad). Spis ale dedime konkretni rysy a vlastnosti od nasich rodicu, kteri je zdedili od svych a az nekde hloub byl nejaky predek konkretni opice atd (prototypicky pripad).

Ve skutecnosti jsou tyto dva pripady pouze hranicni body, a konkretni implementace dedicnosti v ruznych jazycich je posunuta k tedne, nebo druhe strane:

C++: Ciste tridne-instancni, tridy jsou pouze definice, pracuje s nimi pouze kompilator, nejsou to objekty.
Instance nejsou vytvareny tridami, ale specialni konstrukci jazyka – operatorem new.

Java: Uz je o krucek jinde. Tridy maji sve zapouzdrujici objekty, umoznujici s nimi „nejak“ pracovat za behu.
Objekty jsou stale vytvareny operatorem new

SmallTalk, Ruby: Tridy uz jsou plnohodnotne objekty. Vytvareji sve instance svymi metodami a ne zadnym spec. operatorem.

JavaScript: Je bliz protoypicke dedicnosti, ale neni to uplna PD. Proc? Protoze prototyp neprirazujeme objektu, ale jeho konstruktoru.

IO, Self: Ciste prototypicka dedicnost – objekty se vytvareji klonovanim existujicich objektu a pridavani dalsich vlastnosti.
Klonovanim vznikne objekt pouze s referenci na prototyp. Nove vlastnosti se ukladaji do nej.

Kdyz se tedy vratim k tomuto problemu v JavaScriptu, tak je videt, ze je napul cesty. Neni ani tridne-instancni, ani striktne prototypicky (prestoze se tak vetsinou oznacuje).
Kdyz v JS vytvarime novy objekt, neni to „z jineho objektu“ ale „nejakym zpusobem“, pomoci funkce oznacene jako konstruktor. Tento princip je stale blizsi tridne-instancnimu modelu a tudiz neni nijak zavadejici, pouzivat pro funkci, kterou pouzivam jako „vytvarejici“, oznaceni Trida. Je to naopak vhodnejsi, nez mast ctenare hned komplikovanou prototypickou dedicnosti, ktera stejne nektere prvky te tridne-instancni obsahuje.

I v ostatnich vecech, ktere jsou clanku vytykany, se vetsinou jedna o omyly. Snad byly vsechny vyjasneny ostatnimi prispevateli.

Osobne si myslim, ze to, co bylo predmetem tohoto dilu clanku, bylo vysvetelno dobre. Jestli je clanek spravne usporadan, to asi kazdy vnima jinak. Myslim, ze pokud ho docte cely, tak uz mu porozumi, a urcite bude lepsi uceleny dojem, az vyjdou i ostatni dily.

Co bych vytkl ja, je krome drobnosti (to je spis doplneni), ze ve scopu najdete i parametry nadrazene funkce (cili zavadeni lokalni promenne, do ktere se tyto ukladaji, je zbytecne a da se pracovat s parametry name primo), predevsim hodnoceni, ze nektere pristupy jsou spatne a nektere dobre.

V teto diskuzi jsou vsichni odbornici provereni praxi, a tak se i ja budu ohanet tou svou :), ve ktere jsem se uz setkal
s nescetne situacemi, kdy byly vyhodne ruzne pristupy k reseni
dedicnosti. At uz vytvareni vzdy novych objektu, jako je to v prvnim spatnem prikladu – mimochodem pokud chcete rozsirovat nektere built-in objekty prenositelne, tak se tomu nevyhnete, tak jsem casto vyuzil uzavery a metody jako jejich rozhrani.

Je to otazka konkretni situace a ne, ze jedno je spatne, a druhe dobre (resp. treti, co bude prezentovano priste).

Na dalsi dily se urcite tesim a i tento prvni hodnotim kladne.

junix

Pokud trida je takova funkce, kterou pouzivame pri vytvareni objektu pomoci operatoru ‚new‘, pak prvni zpusob nejenze je spatne, ale ani nelze pouzit. To mate pravdu.
Na druhou stranu vytvareni objektu pomoci ‚new‘ neni jediny univerzalni zpusob. Kuprikladu DOM objekty muzete vytvaret pouze pomoci funkci, takze pro vytvoreni konkretniho DOM objektu (napr. DIV element s konkretni css tridou a id) budete muset vytvaret necim podobnym, jako je ten prvni priklad.

Druhy priklad se s vyhodou pouzije nejen u callbacku, ale rozhodne pri elegantnim reseni navrhoveho vzoru state, cili implementaci stavoveho polymorfismu.

Rozhodne se mi libi, ze v JS muzete mit stavovy polymorfismus nejen pro konkretni objekt, ale pro celou „tridu“. Ale to uz nesouvisi s uvednymi priklady.

v6ak

No rozhodně není nutné, abych instanci vytvářel přes new. Existuje tu Factory, což umožňuje některé zajímavé věci v přesunu zodpovědnosti.

junix

Ano, s tim stavovym polymorfismem pomoci uzaveru jsem se spletl.

aprilchild

muzes Dane prosim rozvest, „zneuziti closure“ pro funkcionalni programovani? Resp. uvest nejaky priklad? Mam na mysli ciste funkcionalni priklad, bojim se, ze pouziti closure jde presne proti jeho duchu, zaklinadlem budiz immutable state a no side effects. Neni mi jasne, k cemu bych v cistem navrhu potreboval videl do scope o uroven vys. Ale to je jen spis takova perlicka na zaver – pro puristy:).

Timy

Co třeba toto? Je to v Lispu, ale mělo by to být srozumitelné (násobí to všechny prvky seznamu coef), mapcar dělá prakticky totéž co array.each v MooTools nebo jQuery.

(defun multiply (coef list)
        (mapcar (lambda(x)
                   (* x coef))
           list))

> (multiply 2 '(1 2 3 4))
(2 4 6 8)

Do toho mapcaru (each) posílám anonymní funkci, která musí vidět o scope výše, aby se dostala ke  coef.

aprilchild

Diky!

aprilchild

Diky, vicemene se tvuj (a ostatnich) pragmatismus ohledne closures shoduje s mym nazorem, byt treba v Erlangu bys asi brzy narazil (ne kazdy jazyk je tak ohebna bestie jako JavaScript). Closure pro mutable state je nicmene vytvareni side effects a „ciste“ funkcionalni programovani to neni. Ale za definice nikdo hlavy utinat nebude. Pragmatismus necht (z)vitezi..;).

v6ak

Pořád nechápu, co je na tom za side effect.

aprilchild

Pokud pomoci closure ctu neco v odlisnem scope, side effect nevznika (splnena podminka nemennosti). V pripade, ze stav menit budu (kdybych napr. o uroven vys zvysoval counter apod.), side effect vytvarim a purista by o mem kodu rekl, ze neni funkcionalni. Jsou jazyky, kde jsem tohoto pokuseni usetren (promenne jsou automaticky immutable), v nekterych (js) to mozne je (a v nekterych si restrikce urcuju sam – Scala).

Nekdy se to „necista“ praktika zasahu do stavu jineho scope muze hodit – pokud znam dusledky takoveho pouziti, ale obecne je lepsi se ji vyhybat (lze ji vicemene bezpecne pouzit jen tehdy, kdy jsem si jist, ze dany kod pobezi ‚synchronized‘ pouze v jednom procesu v jeden cas).

Ale to uz je debata o necem jinem, diskuzni vlakno vzniklo jen jako reakce na pouziti closures ve funkcionalnim programovani, ktere Dan zminil.

v6ak

Jo, ale stejnětak může side effect vzniknout bez closure, třeba v párech (Scheme).

hon2a

Rad bych pripojil tento komentar jako protest ci protivahu vetsinou zjevne nepromyslenych nebo argumenty nepodlozenych komentaru uvedenych vyse. Precetl jsem vsechny tri dily serialu a reaguji tedy na serial jako celek.

Vase clanky splnily (a predcily) ma ocekavani a pomohly mi vyjasnit si nektere aspekty implementace „tridni“ dedicnosti v JavaScriptu. Nesouhlasim s vyse uvedenym nazorem, ze rozdeleni prvnich dvou dilu je nevhodne. Prave naopak si myslim, ze rozdeleni je prinosne i z jinych nez technickych duvodu, nebot dava ctenarum prostor, aby se sami pokusili zamyslet nad korektnim resenim problemu.

Naprosto nesouhlasim s opakovanou „kritikou“ Jiriho Hrebenare a dalsich, zpusobenou bud prilis zbeznym prectenim clanku nebo dokonce nepochopenim prave tech principu, jejich nepochopeni tak radi vytykaji Vam, a zalozenou na velmi zmatene argumentaci. Pokud bych po precteni clanku pochyboval o jeho dobre strukturovanosti a vyborne pochopitelnem stylu, staci pro rozptyleni pochyb porovnat Vase clanky s jim uvedenymi odkazy.

Jeste jednou dekuji a preji hodne inspirace pri dalsi tvorbe.

brouk

V té části 2.5.2 „Vylepšené“ třídy nechápu tvrzení, že #nefunguje operátor instanceof,
Animal je typ a proměnná kitty je instancí tohoto typu, tudíž alert(kitty instanceof Animal); vrácí správně true. Jak říkáš, že closure a privilegované metody se pro každou instanci vytváří zas a znova, což je nemalá (a hlavně zbytečná) zátěž, tak níže uvedený zápis je zcela ekvivalentní tvému prototypování, kde uvádíš důkaz, že metody jsou sdílené:
var Animal = function(p_name) {
this.name = p_name;
this.showName = function() {
alert(name);
}
};
var mici = new Animal(‚Mici‘);
var kevi = new Animal(‚Kevi‘);
alert((mici.getName === kevi.getName)); // true
alert((mici.getName === Animal.prototy­pe.getName)); // true
Zajímavé jsou možnosti HTML5:http://www.adobe.com/devnet/html5/articles/javascript-object-creation.html

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.