Co byste měli vědět o Javascriptu [1]: proměnná a globální obor platnosti

prvním díle miniseriálu zmíním jedno z nejznámějších špatných míst Javascriptu. V anglicky psaných zdrojích bývá označován termínem „implied global“. Jde o velice důležitou vlastnost jazyka, jejíž znalost (a hlavně plné pochopení důsledků) vám může ušetřit mnoho vytrhaných vlasů.

K deklaraci proměnné v Javascriptu slouží klíčové slovo var. Často se (a mylně) uvádí, že je jeho použití nepovinné. Ve většině případů má ale deklarace proměnné bez použití var jiný význam.

Vezměme si následující příklad:

function test() {
    var promenna = 10;
    console.log(promenna); //predpokladam dostupnou konzoli - tedy firefox+firebug ci jakukoliv prohlizec s rozumnymi vyvojarskymi nastroji
}

test();
console.log(promenna); //reference error

Zde je korektně deklarována lokální proměnná. Vyzkoušejte si..

Pokud ale klíčové slovo var záměrně či omylem vynecháme, Javascript deklaruje proměnnou v globálním oboru platnosti (alespoň v následujícím příkladu).

function test() {
    promenna = 10;
    console.log(promenna)
}

test();
console.log(promenna); //vypise 10

Vyzkoušejte si..

Tedy přesněji řečeno:

  • při zápisu do proměnné v javascriptu interpret zjistí, zda požadovaná proměnná existuje. Pokud není deklarována jako lokální či parametr, hledá ji v celém „scope chain“ (česky by se asi dalo přeložit jako „zřetězení oborů platnosti“). Tomuto tématu (stejně jako uzávěrům) se ale budu věnovat někdy příště.
  • pokud proměnnou někde nalezne, zapíše do ní přiřazovanou hodnotu
  • pokud ji nenalezne, vytvoří ji v globálním oboru platnosti a zapíše do ní hodnotu.

Je to opravdu tak zlé?

Ano.

  • Pokud nepoužíváte či zapomínáte var, zasviníte si globální obor platnosti spoustou proměnných, které tam nepatří. Obecně je za správnou považována snaha minimalizovat množství globálně platných proměnných, které kód vytváří, na jednu či méně.
  • Snadno mohou vzniknout chyby, které těžko odhalíte:
function cykluj() {
   for (i = 0; i < 10; i++) {
       cyklujvic();
   }
}

function cyklujvic() {
   for (i = 0; i < 5; i++) {
       console.log(i);
   }
}

cykluj();

Vidíte průšvih? Obě funkce pracují se stejnou globální proměnnou. Nejen, že se kód bude chovat jinak, než bylo nejspíš zamýšleno, ale dokonce skončí v nekonečné smyčce (funkce cyklujvic vždy přenastaví proměnnou i a skončí na hodnotě 5, tudíž funkce cykluj nikdy nedojde na konečnou hodnotu). A teď si představte, že dané funkce jsou rozmístěny ve dvou odlišných souborech v jiných částech projektu.

  • můžete se omylem dostat do konfliktu s vlastnostmi objektu window (Globální proměnné jsou totiž vlastnostmi tzv. globálního objektu, kterým je v prohlížeči právě window, v node.js je jím objekt global)
  • tuto situaci ještě komplikuje Internet Explorer, který registruje pro elementy v DOM, které mají nastaven atribut id vlastnost objektu window (tedy globální proměnnou). Pokud se vám pak sejde stejné jméno proměnné jako id nějakého elementu a zapomenete na var, dojde k chybě.

Doporučení na závěr

Používejte klíčové slovo var vždy. Zvolte si vývojové prostředí, které vás na nedeklarovanou proměnnou umí upozornit. Používejte http://jslint.com.

A sledujte RSS nebo twitter, jelikož již brzy vám povím o dalších věcech, které byste o Javascriptu měli vědět.