03.13 Omezení Scope
Výuka
Proč omezení scope?
Proč není dobrý nápad udělat všechny proměnné globální?
// ❌ Všechno globální
var data = [];
var count = 0;
var result = null;
var temp = 0;
var i = 0;
function processData() {
for (i = 0; i < data.length; i++) { // Používá globální i!
temp = data[i] * 2;
count++;
}
}
function calculateSum() {
for (i = 0; i < data.length; i++) { // Také používá globální i!
result += data[i];
}
}
Co se stane, když processData zavolá calculateSum? Konflikt! Obě funkce používají stejné globální i - chaos!
Princip nejmenší expozice (POLE - Principle of Least Exposure) říká: Ukázuj jen minimum, co je nutné. Zbytek skryj.
Proč je to důležité?
- Předejdeš kolizím názvů -
iv jedné funkci neovlivníiv jiné - Chráníš před neočekávaným chováním - nikdo "zvenku" ti nezmění interní proměnné
- Snadnější refaktoring - když je proměnná soukromá, můžeš ji změnit bez obav
Představ si to jako: Úklidová skříňka. Neházíš čisticí prostředky volně po bytě (globální), ale schovaš je do skříňky (lokální scope), kde jsou v bezpečí a nikomu nepřekáží.
Jak to funguje?
Omezení scope = deklaruj proměnné v nejmenším možném scope:
1. Potřebuješ proměnnou jen v bloku? → Dej ji do bloku {}
2. Potřebuješ ji jen ve funkci? → Dej ji do funkce
3. Potřebuješ ji všude? → Teprve pak globální scope
Nástroje pro omezení scope:
- Bloky
{}- slet/constvytvoří block scope - Funkce - každá funkce má vlastní scope
- IIFE - okamžitě volaná funkce pro izolaci
Klíčové koncepty
- POLE - Principle of Least Exposure, minimalizuj viditelnost proměnných
- Block scope -
{}bloky slet/constizolují proměnné - Function scope - funkce vytváří soukromý prostor
- IIFE - Immediately Invoked Function Expression, starý pattern pro izolaci
- Private vs Public - co je soukromé (private) vs co je vystavené (public)
JavaScript
Příklad 1: Problém s globálním scope
// ❌ ŠPATNĚ - všechno globální
var result = 0;
function calculate(numbers) {
var i; // ale stále function scope!
for (i = 0; i < numbers.length; i++) {
result += numbers[i];
}
return result;
}
function double(numbers) {
var i;
for (i = 0; i < numbers.length; i++) {
numbers[i] = numbers[i] * 2;
}
}
calculate([1, 2, 3]); // result = 6
calculate([1, 2, 3]); // result = 12 (wtf?!)
Co se stalo?
resultje globální - není resetovaná mezi voláními!- Druhé volání přičítá k výsledku prvního volání
- Neočekávané chování kvůli sdílenému stavu
Příklad 2: Omezení pomocí block scope
// ✅ DOBŘE - block scope
function calculateSum(numbers) {
let result = 0; // Lokální v funkci
for (let i = 0; i < numbers.length; i++) {
let doubled = numbers[i] * 2; // Block scope!
result += doubled;
}
// doubled zde není dostupné
return result;
}
console.log(calculateSum([1, 2, 3])); // → 12
console.log(calculateSum([1, 2, 3])); // → 12 (vždy správně!)
Co se stalo?
resultje lokální ve funkci - každé volání má vlastníije v bloku for - izolované pro každou iteracidoubledje v bloku for - nepotřebuješ ho venku- Žádné konflikty!
Příklad 3: Proč omezit scope - kolize názvů
// ❌ Globální proměnné = kolize
let count = 0;
function incrementA() {
count++; // Modifikuje globální count
}
function incrementB() {
count++; // Také modifikuje STEJNÝ count!
}
incrementA();
incrementB();
console.log(count); // → 2 (oba ovlivnily stejnou proměnnou)
// ✅ Lokální scope = izolace
function createCounterA() {
let count = 0; // Vlastní count
return () => ++count;
}
function createCounterB() {
let count = 0; // Jiný count
return () => ++count;
}
const counterA = createCounterA();
const counterB = createCounterB();
console.log(counterA()); // → 1
console.log(counterB()); // → 1 (nezávislé!)
console.log(counterA()); // → 2
Co se stalo?
- První příklad: sdílený globální
count- kolize! - Druhý příklad: každá funkce má vlastní
count- izolace ✅
Příklad 4: Block scope s let/const
function processItems() {
const items = [1, 2, 3, 4, 5];
// Dočasná proměnná jen pro tento blok
{
const temp = items.filter(x => x % 2 === 0);
console.log("Sudá čísla:", temp);
}
// temp zde není dostupné!
// console.log(temp); // ❌ ReferenceError
// Další izolovaný blok
{
const temp = items.map(x => x * 2); // Jiný temp, žádná kolize!
console.log("Zdvojená:", temp);
}
return items;
}
processItems();
// → Sudá čísla: [2, 4]
// → Zdvojená: [2, 4, 6, 8, 10]
Co se stalo?
- Bloky
{}slet/constvytvářejí block scope - Každý blok má vlastní
temp tempnení viditelný mimo blok- Čistší kód - proměnné žijí jen tam, kde je potřebuješ
Příklad 5: Funkce pro skrytí implementace
// ❌ Špatně - cache je globální
var cache = {};
function factorial(n) {
if (n < 2) return 1;
if (!(n in cache)) {
cache[n] = n * factorial(n - 1);
}
return cache[n];
}
// cache je veřejná - kdokoliv ji může změnit!
cache[5] = 999; // 💥 Rozbije factorial
// ✅ Dobře - cache je soukromá
function createFactorial() {
const cache = {}; // Soukromá!
return function factorial(n) {
if (n < 2) return 1;
if (!(n in cache)) {
cache[n] = n * factorial(n - 1);
}
return cache[n];
};
}
const factorial = createFactorial();
console.log(factorial(5)); // → 120
console.log(factorial(6)); // → 720 (používá cache)
// cache není dostupná zvenku!
Co se stalo?
- První příklad:
cacheje veřejná - kdokoliv ji může pokazit - Druhý příklad:
cacheje soukromá - chráněná closure - Bezpečnější a čistější API
Příklad 6: IIFE (Immediately Invoked Function Expression)
// Starý pattern pro izolaci scope (před let/const)
// ❌ Bez IIFE - znečišťuje globální scope
var temp = someComplexCalculation();
var result = processTemp(temp);
// temp je nyní globální (nepotřebuješ ji!)
// ✅ S IIFE - temp je soukromá
const result = (function() {
const temp = someComplexCalculation();
return processTemp(temp);
})();
// temp zde není dostupná
// Moderní alternativa - použij blok
const result2 = (() => {
const temp = someComplexCalculation();
return processTemp(temp);
})();
Co se stalo?
- IIFE je funkce, která se okamžitě zavolá
- Vytvoří dočasný scope pro proměnné
- Moderní kód spíš používá bloky
{}nebo moduly
TypeScript
TypeScript respektuje stejná pravidla pro omezení scope!
// ✅ Block scope s typy
function processData(items: number[]): number {
let sum: number = 0;
{
const filtered: number[] = items.filter(x => x > 0);
sum = filtered.reduce((a, b) => a + b, 0);
// filtered je jen v tomto bloku
}
return sum;
}
TypeScript navíc kontroluje:
function calculate(): number {
if (Math.random() > 0.5) {
const result: number = 42;
return result;
}
// ❌ TypeScript error: Variable 'result' is used before being assigned
// return result; // result není v tomto scope!
return 0;
}
TypeScript přidává:
- ✅ Kontrola scope - upozorní na použití proměnné mimo její scope
- ✅ Typová bezpečnost - kontroluje typy v každém scope
- ✅ Lepší refaktoring - editor ví, kde je proměnná použitá
Rozdíl JS vs TS
JavaScript:
function process() {
if (true) {
let result = 42;
}
return result; // 💥 Runtime error: result is not defined
}
process();
TypeScript:
function process(): number {
if (true) {
let result: number = 42;
}
return result; // ❌ Compile error: Cannot find name 'result'
}
process();
Rozdíl:
- JavaScript odhalí chybu při spuštění - když se dostaneš k
return - TypeScript odhalí chybu při psaní - hned vidíš, že
resultnení v scope
Tip
💡 Deklaruj proměnné co nejblíž použití:
// ❌ Špatně - proměnná daleko od použití
function bad() {
const result = [];
const data = [];
const temp = 0;
// ... 50 řádků kódu ...
result.push(processData(data)); // Kde byla result definována?
}
// ✅ Dobře - proměnná blízko použití
function good() {
// ... kód ...
{
const result = [];
const data = getData();
result.push(processData(data));
saveResult(result);
}
}
💡 Používej bloky pro dočasné proměnné:
// ✅ Dočasné výpočty v bloku
function calculate(numbers) {
let total = 0;
{
const doubled = numbers.map(x => x * 2);
const sum = doubled.reduce((a, b) => a + b, 0);
total = sum;
}
// doubled a sum zde nejsou dostupné - méně clutteru!
return total;
}
💡 Vyhni se globálním proměnným:
// ❌ Globální proměnné
let config = {};
let data = [];
function init() {
config = loadConfig();
data = loadData();
}
// ✅ Moduly nebo funkce
function createApp() {
const config = loadConfig(); // Soukromé
const data = loadData(); // Soukromé
return {
getConfig: () => config,
getData: () => data
};
}
const app = createApp();
Kvíz
Který kód správně omezuje scope?
// Kód A
function calculateA() {
let result = 0;
for (let i = 0; i < 10; i++) {
result += i;
}
return result;
}
// Kód B
let result = 0;
function calculateB() {
for (let i = 0; i < 10; i++) {
result += i;
}
return result;
}
✅ - result je lokální ve funkci - každé volání má vlastní result, žádné konflikty
❌ - result je globální - sdílený mezi voláními, může způsobit chyby
❌ - Nejsou stejné - kód A správně omezuje scope, kód B ne
❌ - Kód A je dobrý příklad omezení scope podle POLE
🎯 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ě