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

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ů - i v jedné funkci neovlivní i v 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 {} - s let/const vytvoří 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 s let/const izolují 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?

  • result je 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?

  • result je lokální ve funkci - každé volání má vlastní
  • i je v bloku for - izolované pro každou iteraci
  • doubled je 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 {} s let/const vytvářejí block scope
  • Každý blok má vlastní temp
  • temp není 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: cache je veřejná - kdokoliv ji může pokazit
  • Druhý příklad: cache je 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 result není 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 →

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ě