Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

03.10 Řetězec Scope

Výuka

Proč řetězec scope?

V minulých lekcích jsi viděl, že scope určuje, kde je proměnná viditelná, a že JavaScript hledá proměnné "zevnitř ven". Ale jak přesně probíhá tohle hledání?

const level1 = "Globální";

function outer() {
  const level2 = "Outer";

  function inner() {
    const level3 = "Inner";
    console.log(level1);  // Jak JavaScript najde level1?
  }

  inner();
}

outer();  // → "Globální"

Scope chain (řetězec scope) je cesta, kterou JavaScript sleduje při hledání proměnné. Je to jako řetěz spojující všechny vnořené scope dohromady.

Proč je to užitečné?

  • Předvídatelné chování - víš přesně, kde JavaScript bude hledat
  • Organizace kódu - vnitřní funkce vidí kontext vnějších funkcí
  • Izolace - každý scope má vlastní proměnné, ale může vidět "nahoru"

Představ si to jako: Panenky matryošky - když hledáš něco v nejmenší panenče, podíváš se dovnitř. Pokud to tam není, otevřeš větší panenku, pak ještě větší, až najdeš, co hledáš.

Jak to funguje?

Scope chain = posloupnost scope, kde JavaScript hledá proměnnou:

1. JavaScript začne hledat v AKTUÁLNÍM scope
2. Pokud nenajde, podívá se do NADŘAZENÉHO scope
3. Pokračuje VEN  ke GLOBÁLNÍMU scope
4. Pokud nenajde ANI TAM, vyhodí ReferenceError
5. Jakmile najde první shodu, PŘESTANE hledat

Důležité pravidla:

  • Hledání jde jen jedním směrem - zevnitř ven (nikdy dovnitř!)
  • Hledání se zastaví u první shody - i kdyby bylo víc shod výš
  • Řetězec je statický - určený při psaní kódu, ne při spuštění

Klíčové koncepty

  • Scope chain - posloupnost vnořených scope, kterou JavaScript prochází při hledání
  • Lookup (hledání) - proces hledání proměnné od aktuálního scope ven
  • Směr hledání - vždycky zevnitř ven, nikdy dovnitř nebo napříč
  • První shoda vyhrává - jakmile najde proměnnou, přestane hledat
  • Shadowing - když vnitřní proměnná "zakryje" vnější se stejným jménem

JavaScript

Příklad 1: Základní scope chain

const a = "úroveň 1 (globální)";

function level2() {
  const b = "úroveň 2";

  function level3() {
    const c = "úroveň 3";

    console.log(c);  // Krok 1: Hledá v level3 → NAŠEL ✅
    console.log(b);  // Krok 1: Hledá v level3 → nenašel
                     // Krok 2: Hledá v level2 → NAŠEL ✅
    console.log(a);  // Krok 1: Hledá v level3 → nenašel
                     // Krok 2: Hledá v level2 → nenašel
                     // Krok 3: Hledá v global → NAŠEL ✅
  }

  level3();
}

level2();
// → úroveň 3
// → úroveň 2
// → úroveň 1 (globální)

Co se stalo?

  • JavaScript vždycky začne hledat v aktuálním scope (level3)
  • Pokud nenajde, pokračuje nahoru řetězem (level2 → global)
  • Jakmile najde první shodu, přestane hledat
  • To je scope chain - cesta zevnitř ven!

Příklad 2: Shadowing - zastínění proměnné

const name = "Alice (globální)";

function outer() {
  const name = "Bob (outer)";  // Zakryje globální name

  function inner() {
    const name = "Charlie (inner)";  // Zakryje outer name

    console.log(name);  // Která name?
  }

  inner();
  console.log(name);  // Která name?
}

outer();
console.log(name);  // Která name?
// → Charlie (inner)
// → Bob (outer)
// → Alice (globální)

Co se stalo?

  • Každý scope má vlastní proměnnou name
  • JavaScript použije nejbližší shodu v scope chain
  • Funkce inner vidí jen svojí name (Charlie) - ostatní jsou zakryté (shadowed)
  • Funkce outer vidí jen svojí name (Bob)
  • Globální scope vidí svojí name (Alice)
  • Shadowing = vnitřní proměnná zakryje vnější se stejným jménem

Příklad 3: Hledání se zastaví u první shody

const x = 1;

function level1() {
  const x = 2;

  function level2() {
    const x = 3;

    function level3() {
      console.log(x);  // Najde x = 3 v level2 a PŘESTANE hledat
    }

    level3();
  }

  level2();
}

level1();
// → 3

Co se stalo?

  • JavaScript hledá x v level3 → nenajde
  • Hledá v level2našel! (x = 3)
  • Přestane hledat - nepokračuje k level1 nebo globálnímu scope
  • I když existuje x s hodnotou 2 a 1, JavaScript je nikdy nevidí

Příklad 4: Scope chain jde jen ven, ne dovnitř

function outer() {
  const outerVar = "Jsem v outer";

  function inner() {
    const innerVar = "Jsem v inner";
    console.log(outerVar);  // ✅ Vidí ven do outer
  }

  inner();
  console.log(innerVar);  // ❌ Error: innerVar is not defined
}

outer();

Co se stalo?

  • Funkce inner vidí ven do outer - scope chain jde nahoru ✅
  • Funkce outer nevidí dovnitř do inner - scope chain NEJDE dolů ❌
  • Scope chain je jednosměrný - jen zevnitř ven!

Příklad 5: Každé volání funkce má vlastní scope

function makeCounter() {
  let count = 0;

  return function() {
    count++;
    return count;
  };
}

const counter1 = makeCounter();
const counter2 = makeCounter();

console.log(counter1());  // → 1
console.log(counter1());  // → 2
console.log(counter2());  // → 1 (vlastní count!)
console.log(counter1());  // → 3

Co se stalo?

  • Každé volání makeCounter() vytvoří nový scope s vlastní count
  • counter1 a counter2 mají vlastní scope chain - každý vidí svou count
  • To je closure - funkce si pamatuje scope, ve kterém byla vytvořená
  • O closures více v lekci 14!

Příklad 6: Vizualizace scope chain

const global = "G";        // 🔴 Globální scope

function outer() {         // 🔵 Outer scope
  const outerVar = "O";

  function middle() {      // 🟢 Middle scope
    const middleVar = "M";

    function inner() {     // 🟡 Inner scope
      const innerVar = "I";

      // Scope chain pro inner:
      // 🟡 inner → 🟢 middle → 🔵 outer → 🔴 global

      console.log(innerVar);   // 🟡 Najde v inner
      console.log(middleVar);  // 🟢 Najde v middle
      console.log(outerVar);   // 🔵 Najde v outer
      console.log(global);     // 🔴 Najde v global
    }

    inner();
  }

  middle();
}

outer();

Co se stalo?

  • Scope chain je posloupnost: inner → middle → outer → global
  • JavaScript hledá postupně každý scope, dokud nenajde proměnnou
  • Každý scope vidí všechny nadřazené scope, ale ne podřazené

TypeScript

TypeScript používá stejný scope chain jako JavaScript. Scope chain funguje identicky!

const message: string = "Globální";

function outer(): void {
  const message: string = "Outer";

  function inner(): void {
    const message: string = "Inner";
    console.log(message);  // Scope chain: inner → outer → global
  }

  inner();  // → "Inner"
}

outer();

TypeScript kontroluje scope chain při kompilaci:

const x: number = 10;

function test(): void {
  const y: number = 20;

  function nested(): void {
    console.log(x);  // ✅ TypeScript ví, že x je v scope chain
    console.log(y);  // ✅ TypeScript ví, že y je v scope chain
    console.log(z);  // ❌ Compile error: Cannot find name 'z'
  }

  nested();
}

test();

TypeScript přidává:

  • Kontrola dostupnosti - upozorní, pokud proměnná není v scope chain
  • Lepší IntelliSense - editor ti ukáže všechny dostupné proměnné v scope chain
  • Typová bezpečnost - kontroluje typy napříč celým scope chain

Rozdíl JS vs TS

JavaScript:

const name = "Alice";

function test() {
  console.log(name);  // ✅ Funguje - name je v scope chain
  console.log(age);   // 💥 Runtime error: age is not defined
}

test();

TypeScript:

const name: string = "Alice";

function test(): void {
  console.log(name);  // ✅ Funguje - name je v scope chain
  console.log(age);   // ❌ Compile error: Cannot find name 'age'
}

test();

Rozdíl:

  • JavaScript najde chybu až při spuštění - když JavaScript prohledá celý scope chain a nenajde age
  • TypeScript najde chybu při psaní - analyzuje scope chain bez spuštění kódu

Tip

💡 Shadowing může být matoucí - používej různé názvy:

// ⚠️ Matoucí - stejný název všude
const data = "globální";

function process() {
  const data = "lokální";  // Zakryje globální

  function transform() {
    const data = "vnořená";  // Zakryje lokální
    console.log(data);  // Která data?
  }

  transform();
}

// ✅ Lepší - jasné názvy
const globalData = "globální";

function process() {
  const processData = "lokální";

  function transform() {
    const transformedData = "vnořená";
    console.log(transformedData);  // Jasné!
  }

  transform();
}

💡 Deklaruj proměnné ve správném scope:

// ❌ Špatně - zbytečně globální
let result;

function calculate() {
  result = 42;  // Používá globální proměnnou
  return result;
}

console.log(calculate());

// ✅ Dobře - lokální scope
function calculate() {
  const result = 42;  // Lokální proměnná
  return result;
}

console.log(calculate());

💡 Chápeš scope chain? Zkus předpovědět výsledek:

const x = "A";

function first() {
  const x = "B";

  function second() {
    console.log(x);  // Co vypíše?
  }

  second();
}

first();
// → "B" (scope chain: second → first → global, najde v first)

Kvíz

Co se stane, když JavaScript hledá proměnnou v scope chain?

const value = 1;

function outer() {
  const value = 2;

  function inner() {
    console.log(value);
  }

  inner();
}

outer();

- Globální value je v scope chain, ale není nejbližší

- JavaScript najde value = 2 v outer jako první shodu a přestane hledat

- Shadowing neznamená undefined, jen že vnitřní proměnná má přednost

- Shadowing je legální a běžná součást scope chain

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě