Jmenný prostor (viditelnost proměnných)

Je důležité umět rozlišovat mezi hodnotami a referencemi v kódu, protože tahle vlastnost má zásadní vliv na chování vašeho programu.

AndreaAndrea

Při programování řešíme nejen jak je vhodně pojmenovat proměnné a funkceí, ale i kam je umístit. Pozice v kódu je důležitá pro určení, kdy a kde může být proměnná přístupná a modifikována. Vhodné jméno zase potřebujeme pro to, abysme se nedostali do konfliktu se stejně pojmenovanými proměnnými.

Nicméně i když máme stejně pojmenované proměnné, tak si s stím JS poradí. Běžící program se musí řídit určitou logikou při práci s proměnnými a funkcemi. Tomuto mechanismu říkáme jmenný prostor (scope), který ovlivňuje, jak a kde jsou proměnné a funkce přístupné v kódu.

Jak to funguje?

Paměťový prostor pro proměnnou je vytvořen v momentě, kdy je proměnná deklarována nebo kdy voláme funkci s jejím kontextem. Jakmile ji deklarujete, můžete ji používat a odkazovat se na ní. Když JavaScriptový engine zpracovává náš kod a narazí na proměnnou, v zásadě se ptá na dvě otázky, které souvisí s pozicí proměnné a jejím scopem.

Na jaké pozici se proměnná nachází?

Javascriptový jmenný prostor se definuje lexikálně, nebo staticky. Tak se nazývá způsob, kdy se jmenné prostory určují na základě struktury kódu během kompilace a nemění se v průběhu běhu programu.

Do jakého scope patří?

Scope proměnné určuje, v jaké části kódu je proměnná přístupná a jakou má hodnotu. V JavaScriptu existují dva hlavní typy scopů: lokální a globální.

Když JavaScriptový engine zpracovává kód, hledá deklarace proměnných ve funkcích, blokovém scopu a globálním scopu. Během tohoto procesu engine zjišťuje, zda je proměnná dostupná v daném scopu.

Stínění proměnných (variable shadowing)

V mnohých programovacích jazycích slouží jmenné prostory k tomu, aby názvy proměnných a kód nekolidoval s jinými objekty a proměnnými v globálním jmenném prostoru. Engine také umožňuje stínění proměnných (variable shadowing), což nastává, když je proměnná se stejným jménem deklarována ve vnitřním scopu, a tím "překrývá" stejně pojmenovanou proměnnou v nadřazeném scopu.

Globální a lokální prostor

Rozdíl mezi lokálními a globálními proměnnými je v jejich platnosti a dostupnosti. Obecně lze říci, že proměnná je viditelná minimálně pro tu úroveň kódu (blok, funkce, globální), ve které je deklarovaná.

Práce s lokální proměnnou je skoro vždy rychlejší než odkazování na globální proměnnou.

Největší rozsah viditelnosti mají globální proměnné. Globální proměnné jsou proměnné, které jsou deklarovány mimo jakoukoli funkci nebo objekt a tedy je dostupná (viditelná) v celém skriptu a všech jeho funkcích.

Pokud kód zapíšete do funkce, pak má "lokální rozsah" neboli rozsah, který je dostupný pouze v rámci této funkce. Ve funkcích se dá však ovlivňovat i globální stav aplikace, ale není vhodné to dělat protože to často vede k neočekávaným chybám.

Historicky měly soubory načtené na webové stránce stejný rozsah. To znamená, že globální proměnná deklarovaná v jednom souboru bude viditelná pro kód v ostatních souborech. Rozlišení mezi lokální a globální platností proměnné patří mezi základní programátorskou dovednost.

Rozsah na úrovni funkce

Ve funkcích pak má smysl jít dál a rozlišovat scoping: funkční/lokální a blokový. Ten se pak odvíjí od toho, zda je proměnná deklarována pomocí klíčového slova var, let nebo const.

Pokud deklarujete proměnnou bez klíčového slova var, může být proměnná deklarována jako globální proměnná, nicméně to záleží v jakém režimu se kód spouští. Doporučujeme vždy deklarovat proměnné s klíčovým slovem a vyhnete se komplikacím.

Funkční scoping je způsob omezení platnosti proměnných na úrovni funkce. Funkční scoping se historicky používá pro deklarace proměnných s klíčovým slovem var.

function foo() {
  var x = 10;
  console.log(x);  // vypíše 10
}
console.log(x);  // vyvolá chybu ReferenceError

Ve výše uvedeném příkladu je proměnná x deklarována uvnitř funkce foo a je dostupná pouze uvnitř této funkce. Pokud se pokusíte přistoupit k proměnné x zvenčí funkce, vyvolá se chyba ReferenceError.

Viditelnost v bloku

Bloková viditelnosti (block scoping) se do jazyka dostala plnohodnotně až s verzí ES6, do které byly pro deklarování proměnných přidány klíčové slova let a const. Jde o způsob omezení platnosti proměnných na úrovni bloku.

if (true) {
  let y = 20;
  console.log(y);  // vypíše 20
}
console.log(y);  // vyvolá chybu ReferenceError

Ve výše uvedeném příkladu je proměnná y deklarována pomocí let v bloku if a je dostupná pouze v rámci tohoto bloku.

V samostantém článku ukazujeme příklad, kdy se hodí použít proměnnou s blokovou platností.

V programování je vhodnější používat spíše blokový scope, který přináší výhody: v předvídatelnosti kódu zmenšuje šance na chyby způsobené nechtěným přepsáním nebo přistoupením k proměnné z jiné oblasti.