03.09 Lexikální Scope
Výuka
Proč lexikální scope?
V lekci 08 jsi viděl, že scope určuje, kde je proměnná viditelná. Ale jak JavaScript rozhoduje, která proměnná patří do kterého scope?
const color = "modrá";
function outer() {
const color = "červená";
function inner() {
console.log(color); // Která "color"? Modrá nebo červená?
}
inner();
}
outer(); // → "červená"
Lexikální scope (lexical scope) říká: Kde kód píšeš, tam patří. Ne kde se volá, ne kdy běží - ale kde je napsaný.
Proč je to užitečné?
- Předvídatelnost - stačí se podívat na kód, nemusíš sledovat, odkud se volá
- Čitelnost - vidíš hned, jaké proměnné funkce používá
- Bezpečnost - funkce nemůže "náhodou" přistoupit k proměnným, které by neměla
Představ si to jako: Krabice v krabicích. Vnitřní krabice vidí obsah vnější, ale vnější krabice nevidí dovnitř té menší. Kde krabici umístíš (napíšeš v kódu), tam patří.
Jak to funguje?
Lexikální scope = scope určený tím, KDE kód píšeš:
1. JavaScript při kompilaci "vidí", kde jsou funkce a bloky napsané
2. Vytvoří "scope bubbles" (bubliny scope) - vnořené oblasti
3. Každá bublina vidí proměnné ve svém scope + všech vnějších
4. Při spuštění hledá proměnné ZEVNITŘ VEN (nikdy dovnitř!)
Důležité:
- Scope se určuje při psaní kódu (author-time), ne při spuštění (run-time)
- Nemůžeš změnit scope za běhu programu (až na
evalawith, které NIKDY nepoužívej) - Hledání probíhá jen jedním směrem - zevnitř ven
Klíčové koncepty
- Lexikální = podle místa v kódu - kde funkci/proměnnou napíšeš, tam patří
- Nested scope (vnořené) - scope uvnitř scope, jako krabice v krabici
- Lookup (hledání) - JavaScript hledá proměnnou od nejbližšího scope ven
- Shadowing - vnitřní proměnná "zakryje" vnější se stejným jménem
- One-way street - můžeš hledat jen ven, nikdy dovnitř
JavaScript
Příklad 1: Scope určený místem v kódu
const name = "Globální";
function showName() {
console.log(name); // Kde se podívá? Místně → Ven (globální)
}
showName();
// → "Globální"
function outer() {
const name = "Vnější funkce";
function inner() {
console.log(name); // Kde se podívá? Místně → Ven (outer) ✅
}
inner();
}
outer();
// → "Vnější funkce"
Co se stalo?
- Funkce
showNamenevidí proměnnou místně, tak hledá venku → najde globálníname - Funkce
innernevidí proměnnou místně, tak hledá venku → najdenamezouter - Lexikální scope = kde je funkce napsaná (uvnitř
outer), ne odkud se volá!
Příklad 2: Lookup - hledání zevnitř ven
const a = "úroveň 1";
function level2() {
const b = "úroveň 2";
function level3() {
const c = "úroveň 3";
console.log(c); // ✅ Najde v úrovni 3
console.log(b); // ✅ Hledá ven → úroveň 2
console.log(a); // ✅ Hledá ven → úroveň 2 (nemá) → úroveň 1 ✅
}
level3();
console.log(c); // ❌ Error: c is not defined
}
level2();
Co se stalo?
- JavaScript hledá proměnnou nejdřív lokálně
- Pokud nenajde, hledá v dalším vnějším scope
- Pokračuje až do globálního scope
- Pokud ani tam nenajde, vyhodí chybu
ReferenceError - Nikdy nehledá dovnitř -
level2nemůže vidětczlevel3!
Příklad 3: Shadowing - překrytí proměnné
const value = "vnější";
function test() {
const value = "vnitřní"; // Zakryje vnější value
console.log(value); // Která value? Místní! ✅
}
test();
// → "vnitřní"
console.log(value);
// → "vnější" (globální nezměněna)
Co se stalo?
- JavaScript hledá
valuenejdřív vtestfunkci → najde! ✅ - Přestane hledat - našel nejbližší match
- Vnější
valuestále existuje, ale je zakrytá (shadowed) - Obě proměnné existují zároveň, jen vnitřní má přednost
Příklad 4: Scope se určuje při psaní, ne volání
const color = "červená";
function showColor() {
console.log(color); // Kde hledá? Podle místa DEFINICE!
}
function test() {
const color = "modrá";
showColor(); // Zavolá showColor ZDE
}
test();
// → "červená" (ne "modrá"!)
Co se stalo?
- Funkce
showColorje definovaná v globálním scope - Proto hledá
colorv globálním scope (kde je napsaná) - Nezáleží, že ji voláme z
test(kde jecolor = "modrá") - Lexikální scope = určeno místem definice, ne volání!
Příklad 5: Lookup zastaví u první shody
const x = "globální";
function outer() {
const x = "outer";
function middle() {
const x = "middle";
function inner() {
console.log(x); // Najde v middle a přestane hledat
}
inner();
}
middle();
}
outer();
// → "middle"
Co se stalo?
- JavaScript hledá
xvinner→ nenajde - Hledá v
middle→ najde! ✅ - Přestane hledat - našel první shodu
- Nikdy se nedostane k
xzouternebo globální
Příklad 6: Vnořené funkce vidí "ven"
function makeCounter() {
let count = 0; // Lokální proměnná v makeCounter
return function() {
count++; // Vidí count z vnějšího scope!
return count;
};
}
const counter = makeCounter();
console.log(counter()); // → 1
console.log(counter()); // → 2
console.log(counter()); // → 3
Co se stalo?
- Vnitřní funkce je definovaná uvnitř
makeCounter - Díky lexikálnímu scope vidí proměnnou
countz vnějšího scope - I když
makeCounteruž skončila, vnitřní funkce si pamatujecount - To je closure - o tom více v lekci 14!
TypeScript
TypeScript respektuje stejná pravidla lexikálního scope jako JavaScript. Scope funguje identicky!
const message: string = "Globální";
function outer(): void {
const message: string = "Outer";
function inner(): void {
console.log(message); // Hledá podle lexikálního scope
}
inner(); // → "Outer"
}
outer();
TypeScript kontroluje scope při kompilaci:
const x: number = 10;
function test(): void {
console.log(x); // ✅ TypeScript ví, že x existuje venku
console.log(y); // ❌ Compile error: Cannot find name 'y'
}
test();
TypeScript přidává:
- ✅ Kontrola existence proměnných - varování, pokud proměnná není v žádném dostupném scope
- ✅ Lepší IntelliSense - editor ti ukáže, jaké proměnné jsou v daném scope dostupné
- ✅ Typová bezpečnost - kontroluje typy napříč všemi scope
Rozdíl JS vs TS
JavaScript:
const name = "Alice";
function test() {
console.log(name); // ✅ Funguje
console.log(age); // 💥 Runtime error: age is not defined
}
test();
TypeScript:
const name: string = "Alice";
function test(): void {
console.log(name); // ✅ Funguje
console.log(age); // ❌ Compile error: Cannot find name 'age'
}
test();
Rozdíl:
- JavaScript nenajde chybu, dokud kód nespustíš
- TypeScript najde chybu hned při psaní - editor tě upozorní!
- Obojí používá stejný lexikální scope, ale TS ho kontroluje dřív
Tip
💡 Scope se určuje při psaní, ne volání:
// ❌ Mylná představa - "showColor uvidí color z caller"
const color = "červená";
function showColor() {
console.log(color);
}
function test() {
const color = "modrá";
showColor(); // Myslíš, že vypíše "modrá"?
}
test(); // → "červená" (hledá podle místa DEFINICE!)
// ✅ Správná představa - scope podle místa definice
function test() {
const color = "modrá";
function showColor() {
console.log(color); // Definovaná UVNITŘ test → vidí color z test
}
showColor(); // → "modrá" ✅
}
test();
💡 Shadowing může být matoucí - vyhni se, pokud není nutný:
// ⚠️ Matoucí - stejný název na více místech
const name = "globální";
function test() {
const name = "test"; // Zakryje globální
function inner() {
const name = "inner"; // Zakryje test
console.log(name);
}
inner();
}
// ✅ Lepší - jasné názvy
const globalName = "globální";
function test() {
const testName = "test";
function inner() {
const innerName = "inner";
console.log(innerName);
}
inner();
}
💡 Vnitřní scope nemůže "uniknout" ven:
function outer() {
if (true) {
const secret = "Tajemství";
}
console.log(secret); // ❌ Error: secret is not defined
// secret existuje JEN uvnitř if bloku!
}
// ✅ Pokud potřebuješ proměnnou venku, deklaruj ji venku
function outer() {
let secret; // Deklarace ve vnějším scope
if (true) {
secret = "Tajemství"; // Přiřazení
}
console.log(secret); // ✅ Funguje
}
Kvíz
Co je lexikální scope?
const x = "globální";
function outer() {
const x = "outer";
function inner() {
console.log(x);
}
return inner;
}
const fn = outer();
fn(); // Co vypíše?
❌ - Lexikální scope se určuje místem definice, ne volání
✅ - Funkce inner je definovaná uvnitř outer, proto vidí x z outer
❌ - Díky closure si funkce pamatuje scope, i když outer skončila
❌ - x je dostupná díky lexikálnímu scope a closure
🎯 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 →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
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě