Javascript a oblast působnosti proměnných - díl první
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?
Seriál Javascript a oblast působnosti proměnných
- Javascript a oblast působnosti proměnných - díl první
- Javascript a oblast působnosti proměnných - díl druhý
- Javascript a oblast působnosti proměnných - díl třetí
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í.
Školení Google+ pro firmy

- Jak využít Google+ pro firemní komunikaci a marketing.
- Čím se liší Google+ od Twitteru a Facebooku z pohledu firemního využití.
- Jak využít Google+ v souladu s pravidly užívání.
- Založení Google+ Page (Stránky) krok po kroku, včetně praktických tipů.
Detailní informace o školení Google+ »
Seriál Javascript a oblast působnosti proměnných
- Javascript a oblast působnosti proměnných - díl první
- Javascript a oblast působnosti proměnných - díl druhý
- Javascript a oblast působnosti proměnných - díl třetí
Přehled názorů
Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.