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

Zdroják » Různé » Javascript a oblast působnosti proměnných – díl první

Javascript a oblast působnosti proměnných – díl první

Články Různé

V sérii článků Petra Staníčka se podíváme na jednu z oblastí JavaScriptu, která většině programátorů může připadat samozřejmá a nepřekvapivá, totiž na oblast působnosti proměnných. V prvním článku budou na pořadu dne obyčejné proměnné a funkce. Myslíte si, že máte v problematice jejich působnosti zcela jasno?

Poznámka redakce: Petr Staníček původně napsal jeden velmi dlouhý článek, který by byl na jedno „učtení“ příliš náročný. Proto jsme po vzájemné dohodě sáhli k jeho rozdělení. První část se věnuje věcem, které by měly být programátorům v JS důvěrně známé – totiž obory platností proměnných a funkcí. V druhém díle bude následovat popis objektů, tříd, metod a možností zapouzdření, ve třetím díle pak uzávěry (closures). První díl je tedy jakousi „předehrou“, a proto může připadat zkušenějším jako opakování známých věcí. 

Napsat něco o oblasti působnosti proměnných v Javascriptu jsem se rozhodl hlavně proto, že jsem nedávno v jedné z velmi temných chodbiček této problematiky zabředl až po krk – a nikoli poprvé – a potřebuji si v tom konečně sám udělat jednou provždy trochu jasno. Přesně podle hesla: „Jestli v něčem nemáš jasno, napiš o tom článek. Jestliže to opravdu nechápeš, napiš o tom knihu. A pokud pořád ještě tápeš, začni to učit.“ Ona ta platnost proměnných v Javascriptu je známý problém zavalený spoustou dezinformací, mylných představ i fám a prakticky každý javascriptový programátor na to dříve či později narazil. A tvrdí-li někdo, že s tím nikdy problém neměl, má ho nejspíš dodnes.

Globální a lokální proměnné

Rozlišování mezi lokální a globální platností proměnných patří mezi základní programátorské dovednosti; míra a způsob jejich odlišení zase mezi základní parametry každého programovacího jazyka. Většina jazyků má v tomto ohledu velmi striktní pravidla, u Javascriptu se to může zdát malinko divočejší, ale pravidla jsou tu také. Ovšem v některých případech poněkud méně průhledná.

Obecně lze říci, že každá proměnná má platnost pro tu úroveň kódu, v níž byla deklarována – aneb jak se říká, byla „uvařena“ (kvůli klíčovému slovu var, které se k deklaraci proměnných používá). Pokud je proměnná deklarována na nejvyšší úrovni, tedy přímo v dokumentu, mimo tělo nějaké funkce, stává se tímto okamžikem proměnnou globální a je dostupná z kteréhokoli místa kódu.

var x = 1;function test() {
   x++;
   alert(x);
   }
x = 2;
test();

Globální proměnné x je deklarací přiřazena hodnota 1. Následně na nejvyšší úrovni kódu je jí přizena hodnota 2. Poté je zavolána funkce test(), která její hodnotu zvýší o jedna a vypíše její aktuální hodnotu, tedy 3.

Lokální proměnné

Pokud je proměnná deklarována uvnitř nějaké funkce, její platnost se zužuje pouze na kód uvnitř této funkce. Navíc je zde jeden zásadní rozdíl: tato proměnná nevzniká hned, ale až při volání své „mateřské“ funkce. A voláme-li ji vícekrát, vzniká pokaždé znova.

function test() {
   var x = 1;
   alert(x);
   x++;
   }
test();
test();

Při načítání skriptu vznikne funkce test, ovšem nic z toho, co definuje její kód – tedy ani proměnná x  – ještě neexistuje. Teprve při volání test() vznikne (lokální) proměnná x, dostane hodnotu 1, ta se vypíše, její hodnota se zvýší o 1 a funkce skončí. Tím tato proměnná x zaniká. Dalším voláním test() se vytvoří nový „klon“ proměnné x a stane se totéž – tj. vypíše se 1, hodnota x se zvýší o jedna, načež zanikne.

Lokální proměnná se uvnitř své „mateřské“ funkce chová jako globální, je tedy dostupná celé této úrovni kódu, tedy i všem funkcím deklarovaným uvnitř uzavírající funkce.

function test() {
   function plus() {
      x++;
      }
   var x = 1;
   plus();
   alert(x);
   }
test();

Zavolá se funkce test(), ta deklaruje svou lokální funkci plus, poté deklaruje svou lokální proměnnou x s hodnotou 1, zavolá funkci plus pro kterou je x proměnnou globální, zvýší tedy její hodnotu o jedna a výsledná hodnota 2 se vypíše.

Je důležité vědět, že mezi globálními a lokálními proměnými stejného jména není vůbec žádná vazba a mohou tedy existovat dvě různé proměnné se stejným jménem, ale odlišným oborem působnosti.

function test() {
   var x = 1;
   alert(x);
   }
var x = 10;
test();
alert(x);

Zde se nejprve deklaruje funkce test, poté globální proměnná x s hodnotou 10. Poté se volá funkce test(), která si vytvoří svou lokální proměnnou x s hodnotou 1, a tu zobrazí. Načež se zobrazí hodnota jiné, tentokrát globální proměnné x, tedy 10.

Vše je lepší uvařené

Jedním z největších zel Javasciptu je skutečnost, že explicitní deklarování proměnných není povinné. Nicméně jeho nepoužívání může vést k řadě problémů a skrytých chyb a je dobrým zvykem slušného programátora vařit úplně každou proměnnou – především právě proto, aby měl zcela jasno v mezích její platnosti.

Pokud se tak z jakéhokoli důvodu nestane, je aspoň důležité vědět, že neznámé (nedeklarované) proměnné se při prvním použití automaticky deklarují na globální úrovni.

function test() {
   x = 10;
   alert(x);
   }
test();
x++;
alert(x);

Zde se volá funkce test(), která přiřazuje hodnotu 10 dosud nikde nedeklarované proměnné x, proto se automaticky vytvoří globální proměnná x a zobrazí se její hodnota 10. Poté globální část kódu této (již deklarované!) proměnné zvýší hodnotu o jedna a následně zobrazí hodnotu 11.

Je opravdu důležité si na tuto vlastnost Javascriptu dávat dobrý pozor, nezřídka se stává, že takováto nedeklarovaná proměnná je použita domněle jako lokální – třeba pro index pole nebo řídicí proměnnou cyklu – ale protože je ve skutečnosti proměnnou globální, její hodnotu někdo zvenčí neočekávaně změní a mohou se začít dít jen těžko odhalitelné chyby. Deklarování proměnných by si měl každý dát za pravidlo i v těch nejmenších a nejpitomějších skriptících – a pokud píšeme nějakou knihovnu nebo vůbec jakkoli sdílený kód, který se může ocitnout ve stránce společně s kódy, které nemáme plně pod svou kontrolou, je to zcela bez diskuse a mělo by to být naprosto povinné.

Proměnné a funkce

Dosud jsem mluvil jen o proměnných, nicméně z hlediska Javascriptu se jako proměnná chová i každá funkce a platí pro ně totéž, co bylo řečeno o proměnných výše. Obvyklý zápis funkce je v podstatě zkrácený zápisem deklarace proměnné a přiřazením funkce jako její hodnoty – neboli tento tvar:

function test(a) {
   return a + 1;
   }

je ekvivalentní tomuto zápisu:

var test = function test(a) {
   return a + 1;
   }

A tak stejně jako proměnné, i funkce definované na globální úrovni jsou globální a dostupné v celém kódu, funkce definované v těle jiné funkce jsou lokální, dostupné jen pro její kód a z hlediska vnějšího kódu neexistují.

function test() {
   function plus(x) { return x + 1 }
   alert( plus(1) );
   }
test();
alert( plus(1) );

Zde se zavolala funkce test, která volá svou interní funkci plus, která zvýší předaný parametr o jedničku. Poté se úplně stejně volá funkce plus z globální úrovně, ale tam již taková funkce neexistuje, což vyvolá chybu Javascriptu.

V dalším díle se podíváme na problematiku tříd a metod, vlastnosti objektů a zapouzdření.

Komentáře

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

var test = function test(a) { … }

V sekci o funkcích je podobný kus kódu, správně ale nejspíš má být takhle (?): var test = function (a) { … }

Aleš Roubíček

I tento zápis je správný. V prvním případě, se do proměnné test přiřazuje pojmenovaná funkce, v druhém případě funkce anonymní. Výhodou prvního případu je, že se v některých debugovacích nástrojích mnohem lépe orientuje v call stacku.

karf

Souhlas, zápis var test = function test(a) { … } má trošku jiný význam a není moc doporučeníhodný. Viz perfektní rozbor na toto téma: http://yura.thin­kweb2.com/named-function-expressions/

ah01

Specifikace říká, že pokud použiji výraz function identifikator(){ … }, tak identifikator bude dostupný pouze uvnitř této fce. (třeba pro potřeby rekurze). Takže následující kód způsobí chybu (IE toto nerespektuje). 

var verejny_nazev = function soukromy_nazev(){ … };
soukromy_nazev(); // Chyba

Nemyslím si, že by toto použitelné v praxy (navíc, když v IE to nefunguje). Zmiňuji to kuli uvedenému zápisu var test = function test(a) { … }. Pokud bych později potřeboval přejmenovat tuto fci. a jméno změnil jen na jednom místě, můžu se dostat do problémů.

PS: toto uvádí i článek, který zmiňuje Karel Fučík. Ono těch zájímavostí/zá­ludností ohledně deklarace funkce je víc, takže pokud vás to zaujalo, přečtěte si ho.

karf

Anonymní funkce na sebe může odkazovat pomocí arguments.callee. Tím je možná i rekurze.

karf

Ani na okamžik jsem nepochyboval, že by Petr Staníček neznal arguments.callee. Ovšem jako začátečník bych si z věty „Pokud je funkce anonymní, tak na sebe zevnitř nemůže odkazovat a nelze např. pracovat s rekurzí.“, ať už byla myšlena v jakémkoli kontextu, nejspíš odnesl zcela jednoznačný a zcela mylný závěr. Proto moje poznámka (nebyla myšlena jako rejpání).

Dero

Díky za odpověď, pixy, šlo mi jen o to, zda ses neupsal. Přiřazovat pojmenovanou funkci proměnné téhož jména není totiž v praxi příliš běžné, proto jsem se nad tím pozastavil. Nicméně rekurze v anonymních funkcích nepředstavuje problém (arguments.callee).

Dero

Pardon, nepřečetl jsem si příspěvek Karla Fučíka nade mnou.

blizz.boz

javascript je zlý jazyk so zlým návrhom. ešteže existujú projekty ako Script# ktoré umožnujú písť JS aplikácie v jazyku C#.

a inak perfektný článok…

Aleš Roubíček

JavaScript je zlý neni. To, že vám nevyhovuje, neznamená, že je špatný. Možná, že ste zlý hráč a neviete JavaScript. ;)

blizz.boz

Asi pred tromi rokmi som vytvoril Ajaxovú open source komponentu JoomlaComment! ktorá sa dnes používa na celom svete, ale keď som robil klientskú časť tej komponenty tak som celý čas nadával a veľa nechýbalo k tomu aby som počítač hodil o zem, JavaScript je ešte vačšia prasárna ako PHP. Že je JS zlý jazyk ukazuje aj tento článok citujem:

„Jedním z největších zel Javasciptu je skutečnost, že explicitní deklarování proměnných není povinné. Nicméně jeho nepoužívání může vést k řadě problémů a skrytých chyb a je dobrým zvykem slušného programátora vařit úplně každou proměnnou – především právě proto, aby měl zcela jasno v mezích její platnosti.“

inak odporúčam tento blog s poetickým názvom: Javascript ZLO 2.0:

Aichi

Každému co jeho jest. Je zlo C++, že nemá garbage collector? Uržitě je a stejně ho používá hodně programátorů. To že pán z toho blogu nechápe javascript je jeho problém. JavaScript určité konstrukce umožňuje a je nutné se je naučit, pokud ho chceš používat. Takhle můžeš potom pranýřovat Rupy, Smalltalk a další … Nicméně většinou použiješ takový kód, kterému věříš a máš ozkoušeno, že ti nemění funkčnost pod rukama.

blizz.boz

C++ je jazyk určený na tvorbu systémov driverov atď, je to dobrý jazyk len je trochu náročné na čas v ňom programovať. ale pokiaľ viem managed C++ už má garbage collector.

A pán z toho blogu veľmi dobre chápe JavaScript, veď v tých článkoch práve poukazuje na slabiny tohto jazyka, podrobne ich tam popisuje. JavaScript je zlý jazyk, každý kto v ňom musel naprogramovať vačšiu aplikáciu naň nadával, JS vznikal postupne a je to nekonzistentný zlepenec plný chýb, každý prehliadač ho podporuje ináč a písať JS bez použitia nejakého sofistikovaného Frameworku je doslova peklo.

Aichi

Vašemu komentáři se nedá vůbec věřit a to proto, že používáte slovo každý. Já si třeba na JavaScript nestěžuji. Co vám příjde nekonzistentní? Jaký jazyk nevznikal postupně? pokud vím, tak C/C++ má několik norem, jak vývoj postupoval. Jaké chyby v JavaScriptu máte na mysli? Nemyslíte tím spíš jeho implementace? Mě se zdá, že na „takové to domácí skriptování“ moc rozdílů mezi prohlížeči implementujícími JavaScript nenarazíte.

mykhal

super užitečný článek pro člověka, který javascript používá jako nástroj a neměl zatím čas se pohroužit do jeho teoretických základů.

v6ak

Cituji poslední příklad:

function test() {
function plus(x) { return x++ }
alert( plus(1) );
} test(); alert( plus(1) );

Opravdu funkce plus zvyšuje hodnotu o jedničku? Zvyšuje to jen uvnitř (implementační detail), ale navenek je to úplně jedno: proměnná x není volána odkazem (to v JS asi ani nejde) a postfixový operátor vrací původní hodnotu konvertovanou na číslo.

Samozřejmě, poslední řádek způsobí chybu, s tím souhlasím.

v6ak

No +1 místo ++ by tomu neubralo na srozumitelnosti, spíše naopak. Ad volání odkazem: ve chvíli, kdy do této proměnné něco přiřadím, není tím ovlivněno nic mimo funkci. Tomu neříkám volání odkazem. Je to vlastně stejně jako u Javy, ta taky nemá volání odkazem, i když můžu samozřejmě předat referenci na objekt.

v6ak

// použití v praxi Doplním, že klasický for cyklus v kombinaci s globální proměnnou místo lokální může znamenat zavyklení při rekurzi:

function myFunc(something){

// žádné var i!
for(i=0; i<something.lenght; i++){

if(…){
myFunc(somethin­g[i].subSomet­hing);// rekurze
};

};
… }

Toto může vést ke snížení hodnoty i v průběhu cyklu a často následně k zacyklení. Navíc zde je pak provedeno část iterace s jinou hodnotou i, což způsobí další nepořádek.

Michal Augustýn

Velmi pěkný článek. Jen bych si dovolil malou poznámku k této větě: „Pokud je proměnná deklarována na nejvyšší úrovni, tedy přímo v dokumentu, mimo tělo nějaké funkce, stává se tímto okamžikem proměnnou globální a je dostupná z kteréhokoli místa kódu.“.

Použití slova „dokument“ považuji za velmi nešťastné. V JavaScriptu je tou nejvyšší úrovní globální objekt. Co je tím globálním objektem pak už záleží na konkrétním nasazení JavaScriptu. Pokud se máme bavit o prohlížečích, tak to je objekt „window“, nikoliv „document“. Zkuste si „alert(this === window);“ a „alert(this === document);“.

Daniel Steigerwald

Jen bych dodal, že „mimo tělo nějaké funkce“ je rovněž nešťastná formulace, jakoby globální proměnná nešla definovat přiřazením na globální objekt, např. window.iamGlobal = true;

Daniel Steigerwald

Ježíš Pixy, přestaň používat zavádějící zmatečnou kvaziterminologii, vycházející s podivných překladů DOM pojmů, jejichž význam článek navíc ne zcela jasně objasňuje. :)

Co to proboha je „úroveň HTML dokumentu“? Chvíli sem si lámal hlavu, než sem přišel na to odkud vítr vane… Patrně půjde o script ve stránce? A co když je script externí? Dle tvé logiky by šlo o „úroveň externího souboru“ ;)

Vřele doporučuji používat anglické pojmy, z českým překladem v závorce. Chudák začátečník, poté co překoná tvých x kapitol věnovaných varu, deklaraci a jejich romantickému vztahu k objektu window, bude totálně zmaten, až se začte například do https://develo­per.mozilla.or­g/en/Core_JavaS­cript1.5_Refe­rence, neb zpětným překladem se správného termínu nedobere. Chápu, že sis potřeboval někam sesumarizovat svoje zkušenosti s javascriptem, ale nevím jestli je zdroják vhodné místo ;)

Tvrdit, že anonymní funkce se nedá použít v rekurzi prozrazuje hlubokou neznalost javascriptu.

KLoK

Clovece, nechcete jit zakum pate tridy vysvetlovat, ze soucet uhlu trojuhelniku je pravdepodobne 180 stupnu? Tedy za predpokladu, ze je nakreslen v euklidovske rovine a ze to muze byt take o neco vic nebo min v zavislosti na prostoru ve kterem se pohybujem.

Ja jsem presel k webovym aplikacim z jazyka C, odkud si clovek prinasi urcite navyky ktere nejsou ke skode. Napr. deklarace promenych pred prvnim pouzitim. Z JS pouzivam vyhradne jQuery a jeho rozsireni. Diky tomu jsem na problemy popisovane p. Stanickem zatim nemel to „stesti“ narazit.

A diky za takovy clanek, ktery naprosto srozumitelnou formou osvetli, ze muze k takovemu problemu dojit a hlavne za vysvetleni co ho muze zpusobit.

Leoš Ondra

Pokud globální proměnné neuvaříte, pak si přiděláte problémy hlavně v IE. Kód

<p id=„x“>Odstavec v html</p>

<script …> x = 5; </script>

způsobí chybu Objekt tuto vlastnost nebo metodu nepodporuje, a pokud budete pátrat jaký proboha objekt, pak zjistíte, že ho za vás iniciativně vytvořil IE sám – je jím odkaz na element s id=„x“. Pokud se kod zmeni na

var x = 5;

nebo

var x; x = 5;

pak máte o problém míň.

Leo

v6ak

Myslím, že v tomto kontextu můžeme zmínit tento hack: (function(){
var foo;
… })(); Funguje to obdobně jako toto v Javě, C, C++, …: {
type foo;
… };

Daniel Steigerwald

Volání anonymní funkce není žádný hack :)

v6ak

Prvně je potřeba definovat „hack“ a pak můžeme diskutovat o tom, zda to je nebo není hack. Pro mě je to nezamýšlené použití, byť může být v souladu s normou. Každopádně toto využití považuji za užitečné.

Daniel Steigerwald

Hack je něco, co něco (jiného) „znásilňuje“ :) Tvůj příklad je velmi užitečný a bylo dobré ho zmínit, výhrady sem měl pouze k použití pojmu „hack“.

Pro upřesnění, za hack považuji třeba resetování dontEnum attributu na nativních funkcích, například:

var push = Array.prototype.push; delete Array.prototype.push Array.prototype.push = push;

K čemu to je dobré? for in na Array.prototype náhle najde i push funkci, což se hodí při vytváření array-like objektů. Více, až zveřejním svůj framework ,–)

v6ak

Tento konkrétní hack nepovažuju za šťastné řešení – použití kódu, který vyžaduje hack spolu s kódem, který se spoléhá na standardní chování, je prakticky nemožné. Lepší by bylo napsat nástroj, který umožní procházet i tyto položky, např pomocí for(i in MyTool.Array)… . Název MyTool jsem použil, protože se mi nechtělo hledat nic lepšího. Důležité je, že standardní chování je zachováno. Jinak já opravdu neznám žádnou definici slova hack. Pokud někdo má, rád ji uvítám.

Martin Malý

Ad hack – definice z Wikipedie nestačí? „Hack has several related meanings in the technology and computer science fields. It may refer to a clever or quick fix to a computer program problem, or to what may be perceived to be a clumsy or inelegant (but usually relatively quick) solution to a problem. The term is also used to refer to a modification of a program or device to give the user access to features that were otherwise unavailable, such as DIY circuit bending.“

Daniel Steigerwald

No, jen dodám, že Sheer framework umožňuje modifikaci prototype všech nativních metod, přesto nijak neovlivňuje prostředí ve kterém běží. Tedy, všechny finesy PrototypeJS a Mootools frameworků, jenž modifikují prototype, avšak s žádným negativním dopadem na prostředí ve kterém běží. Prostě znám způsob, jak ohnout js jakkoliv, aniž by se bylo třeba obávat dopadů na ostatní kód. Tohle je hack. Volání anononymní metody hack není.

v6ak

Hmm, tak to mě napadá jen: (function(Array){
… })(AFramerowk­.getModifiedTy­pe(Array, {
push: Array.prototy­pe.push }));

Možná existuje ještě něco jiného (nemyslím obdoby tohoto řešení na stejném principu), ale to neznám.

V každém případě změna lokálního prostředí nebude škodlivá, to je pak něco jiného.

Daniel Steigerwald

.. abych jen nekybicoval, jak bych to napsal já.

Proměnou deklarujeme pomocí klíčového slova „var“, např.

var bla = 'foo'.

To var tam dávejte vždycky, poběží to sice bez toho, ale koledujete si zbytečně o problémy, protože proměnná tak bude globální a jelikoz Internet Explorer propaguje všechny ID elementů do globálního scope, může dojít ke kolizi názvů.

Funkci deklarujete bud tak, ze ji pojmenujete:

function foo() {}

nebo priradite anonymní funkci deklarované proměnné:

var foo = function() {}

Kombinace obou přístupů je možná, ale zbytečná.

Chcete-li 100% crossbrowser přístup, tak na pojmenované funkce zapomeňte, prohlížeče je interpretují rozdílně. Třeba safari nadeklaruje i tuto funkci:

if (false) function foo(){};

takže vždy psát:

var foo = function() {};

Jakmile proměnou deklarujete, můžete ji používat a odkazovat se na ní. Jaká je její viditelnost? Proměnná je viditelná v celém scope(rozsahu) funkce, ve které je definovaná. Pokud není definovaná ve funkci, je viditelná všude, tedy globální.

Co to znamená scope? Všechno uvnitř nějaké funkce:

var foo = function() { // tady je scope foo var bla = function() { // tady je scope bla } }

Scope funkce, jak je vidět, tedy může být zanořený. Zanořovat lze do alelůja, vydáme-li se však opačným směrem, skončíme u objektu window (pakliže se bavíme o javascriptu v prohlížečích).

Další díl: co je to „context“ a jak funguje „this“.

:)

Martin Malý

… zbývá tedy jediná otázka: A proč to tedy nenapíšete jako článek a nenabídnete redakci?

Timy

Není zažitým překladem scope „prostředí“? Nebo je to zažité jen u nás na škole? :-) Klasicky u nás říkáme lexikální prostředí (lexical scope) a lexikální uzávěr (lexical closure).

Borek Bernard

Řekl bych, že překlad „prostředí“ moc zažitý nebude. Já ho třeba slyším prvně :)

Daniel Steigerwald

Já jsem oba pojmy už slyšel, na „úzávěr“ se totiž nedá zapomenout :) Každopádně google vrací na „lexikální prostředí“ 18 výsledků, takže asi moc zažitý skutečně nebude :-) „úroveň HTML dokumentu“ pana Staníčka pak odkazy dva :)

povinná

„scope“ jako „prostředí“ opravdu zažité nebude, nicméně „scope“ jako „obor platnosti“ a „environment“ jako „prostředí“ zažité jsou.

PetrP

Článek není součástí seriálu, nelze se na něj dostat z ostatních dílu.

Johny_S

Zdravím, v první řadě bych chtěl poděkovat za článek. V JS jsem začátečník, zkoušel jsem proto jednoduchý příklad.

<script type=„text/ja­vascript“>

var a;

function text() {
a = 5;
}
</script>

Není mi jasné proč se do proměnné „a“ deklarované před funkcí, se v těle funkce nepřiřadí hodnota „5“. Tuto hodnotu bych potřeboval použít i v jiných funkcích. Funkci volám při načtení stránky.

Díky za odpověď JS

v6ak

No nevím, co děláš, ale toto mi podle očekávání vypíše undefined a 5:

var a;

function text() {
a = 5;
};

alert(a);
text();
alert(a);

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.