Na navigaci | Klávesové zkratky

Var, Let, Const: Přestaňte si komplikovat život v JavaScriptu

JavaScript nabízí tři způsoby, jak deklarovat proměnné: var, let a const. Pro mnoho programátorů není úplně jasné, kdy kterou z nich použít, většina tutoriálů a linterů vás nutí používat je špatně. Pojďme si ukázat, jak psát čistší a srozumitelnější kód bez zbytečných pravidel, která nám ve skutečnosti nepomáhají.

Začněme tím nejnebezpečnějším

JavaScript má jednu zákeřnou vlastnost: pouhým opomenutím deklarace proměnné můžete nevědomky používat globální proměnnou. Stačí zapomenout na var, let nebo const:

function calculatePrice(amount) {
	price = amount * 100;    // Opomenutí! Chybí 'let'
	return price;            // Používáme globální proměnnou 'price'
}

function processOrder() {
	price = 0;               // Používáme tu samou globální proměnnou!
	// ... nějaký kód volající calculatePrice()
	return price;            // Vracíme úplně jinou hodnotu, než čekáme
}

Tohle je noční můra každého vývojáře – kód funguje zdánlivě správně, dokud nezačne někde jinde v aplikaci něco záhadně selhávat. Debugování takových chyb může zabrat hodiny, protože globální proměnná může být přepsána kdekoliv v aplikaci.

Proto je naprosto zásadní vždy deklarovat proměnné pomocí let nebo const.

Zapomeňte na var

Klíčové slovo var je v JavaScriptu od jeho počátku v roce 1995 a nese s sebou pár problematických vlastností, které byly v době vzniku jazyka považovány za features, ale časem se ukázaly jako zdroj mnoha chyb. Po dvaceti letech vývoje jazyka se autoři JavaScriptu rozhodli tyto problémy řešit – ne opravou var (kvůli zachování zpětné kompatibility), ale představením nového klíčového slova let v ES2015.

Na internetu najdete spoustu článků rozebírajících problémy var do nejmenších detailů. Ale víte co? Není potřeba se v tom babrat. Berme var prostě jako překonaný archaismus a pojďme se soustředit na moderní JavaScript.

Kdy použít let

let je moderní způsob deklarace proměnných v JavaScriptu.

Příjemné je, že proměnná existuje vždy pouze uvnitř bloku kódu (tedy mezi složenými závorkami), kde byla definována. To dělá kód předvídatelnější a bezpečnější.

if (someCondition) {
	let temp = calculateSomething();
	// temp je dostupná jen zde
}
// temp už zde neexistuje

V případě cyklů je deklarace přísně vzato umístěna před složenými závorkami, ale nenechte si tím zmást, proměnná existuje jen v cyklu:

for (let counter = 0; counter < 10; counter++) {
	// Proměnná counter existuje jen v cyklu
}
// counter už zde nejsou dostupné

Kdy použít const

const slouží k deklarování konstant. Typicky jde o důležité hodnoty na úrovni modulu nebo aplikace, které se nikdy nemají měnit:

const PI = 3.14159;
const API_URL = 'https://api.example.com';
const MAX_RETRY_ATTEMPTS = 3;

Je ale důležité pochopit jeden klíčový detail: const pouze zabraňuje přiřazení nové hodnoty do proměnné – neřeší, co se děje s hodnotou samotnou. Tento rozdíl se projevuje zejména u objektů a polí (pole je ostatně také objekt) – const z nich nedělá immutable objekty, tj. nezabraňuje změnám uvnitř objektu:

const CONFIG = {
	url: 'https://api.example.com',
	timeout: 5000
};

CONFIG.url = 'https://api2.example.com';  // Toto funguje!
CONFIG = { url: 'https://api2.example.com' };  // Toto vyhodí TypeError!

Pokud potřebujete skutečně neměnný objekt, musíte jej nejprve zmrazit.

Dilema let vs const

Nyní se dostáváme k zajímavější otázce. Zatímco u var vs let je situace jasná, použití const je předmětem mnoha diskuzí v komunitě. Většina tutoriálů, style-guides a linterů prosazuje pravidlo „používej const všude, kde můžeš“. Takže použití const vídáme zcela běžně v tělech funkcí nebo metod.

Pojďme si vysvětlit, proč je tato populární „best practice“ ve skutečnosti anti-pattern, který dělá kód méně čitelný a zbytečně svazující.

Přístup „pokud se proměnná v kódu nepřepisuje, měla by být deklarována jako const“ se na první pohled jeví logický. Proč by jinak bůh stvořil const? Čím víc „konstant“, tím bezpečnější a předvídatelnější kód, že? A navíc rychlejší, protože ho kompilátor může lépe optimalizovat.

Jenže celý tento přístup je ve skutečnosti nepochopení toho, k čemu konstanty slouží. Jde především o komunikaci záměru – opravdu chceme sdělit ostatním vývojářům, že do této proměnné se už nesmí nic přiřadit, nebo do ní jen náhodou v současné implementaci nic nepřiřazujeme?

// Skutečné konstanty - hodnoty, které jsou konstantní ze své podstaty
const PI = 3.14159;
const DAYS_IN_WEEK = 7;
const API_ENDPOINT = 'https://api.example.com';

// vs.

function processOrder(items) {
	// Toto NEJSOU konstanty, jen náhodou je nepřepisujeme
	const total = items.reduce((sum, item) => sum + item.price, 0);
	const tax = total * 0.21;
	const shipping = calculateShipping(total);
	return { total, tax, shipping };
}

V prvním případě máme hodnoty, které jsou konstantami ze své podstaty – vyjadřují neměnné vlastnosti našeho systému nebo důležitá konfigurační data. Když někde v kódu vidíme PI nebo API_ENDPOINT, okamžitě chápeme, proč jsou tyto hodnoty konstanty.

V druhém případě používáme const jen proto, že zrovna teď náhodou hodnoty nepřepisujeme. Ale není to jejich podstatná vlastnost – jsou to běžné proměnné, které bychom v příští verzi funkce klidně mohli chtít změnit. A když to budeme chtít udělat, const nám v tom bude zbytečně bránit.

V dobách, kdy byl JavaScript jeden velký globální kód, mělo smysl snažit se zabezpečit proměnné proti přepsání. Ale dnes píšeme kód v modulech a třídách. Dnes je běžné a správné, že scope je malá funkce a v jejím rámci vůbec nemá smysl rozdíl mezi let a const řešit.

Protože to vytváří naprosto zbytečnou kognitivní zátěž:

  1. Programátor musí při psaní přemýšlet: „Budu tuhle hodnotu měnit? Ne? Tak musím dát const…“
  2. Čtenáře to ruší! Vidí v kódu const a ptá se: „Proč je tohle konstanta? Je to nějaká důležitá hodnota? Má to nějaký význam?“
  3. Za měsíc potřebujeme hodnotu změnit a musíme řešit: „Můžu změnit const na let? Nespoléhá na to někdo?“

Používejte jednoduše let a tyto otázky nemusíte vůbec neřešit.

Ještě horší je, když toto rozhodnutí dělá automaticky linter. Tedy když linter „opraví“ proměnné na const, protože vidí jen jedno přiřazení. Čtenář kódu pak zbytečně přemýšlí: „Proč tady musí být tyto proměnné konstanty? Je to nějak důležité?“ A přitom to není důležité – je to jen shoda okolností. Nepoužívejte v ESLint pravidlo prefer-const!

Mimochodem, argument o optimalizaci je mýtus. Moderní JavaScript engine (jako V8) dokáže snadno detekovat, zda je proměnná přepisována nebo ne, bez ohledu na to, jestli byla deklarována pomocí let nebo const. Takže používání const nepřináší žádný výkonnostní benefit.

Implicitní konstanty

V JavaScriptu existuje několik konstrukcí, které implicitně vytvářejí konstanty, aniž bychom museli použít klíčové slovo const:

// importované moduly
import { React } from 'react';
React = something; // TypeError: Assignment to constant variable

// funkce
function add(a, b) { return a + b; }
add = something; // TypeError: Assignment to constant variable

// třídy
class User {}
User = something; // TypeError: Assignment to constant variable

Je to logické – tyto konstrukce definují základní stavební bloky našeho kódu a jejich přepsání by mohlo způsobit chaos v aplikaci. Proto je JavaScript automaticky chrání proti přepsání, stejně jako kdyby byly deklarovány pomocí const.

Konstanty ve třídách

Třídy byly do JavaScriptu přidány relativně nedávno (v ES2015) a jejich funkcionalita teprve postupně dospívá. Například privátní členy označené pomocí # přišly až v roce 2022. Na podporu konstant ve třídách JavaScript stále čeká. Prozatím můžete používat static, který ale není zdaleka to samé – označuje hodnotu sdílenou mezi všemi instancemi třídy, nikoliv však neměnnou.

Závěr

  1. var nepoužívejte – je to přežitek
  2. const používejte pro skutečné konstanty na úrovni modulu
  3. Ve funkcích a metodách používejte let – je to čitelnější a jasnější
  4. Nenechte linter automaticky měnit let na const – není to o počtu přiřazení, ale o záměru

před 16 dny v rubrice Random | blog píše David Grudl | nahoru

Mohlo by vás zajímat

Komentáře

  1. Ahoj #1

    avatar

    Zdravím.
    Jsem Javascripťák/TS se znalostí Cčkových jazyků.

    Souhlasím, že v moderním JS/TS nemá var moc místa.
    Var/let/const je ale stejně věčný boj, který vzhledem k množství lidí, co proudí do IT a neznají důvody jejich zavedení, a kterým je to úplně u …, nemůžeme vyhrát.

    Nejvíc mě dráždí, když někdo říká konstantám definovaným s const proměnná.

    Co je ale důležité, tak použít const tam, kde se s hodnotou nebude hýbat a let tam, kde ano, používat Typescript a dodržovat typy. Rozeznat primitivní a složené typy.

    Např. Const pro Promise, což je víceméně jednorázový identifikátor.
    Nebo const pro objekty/pole, které se vytvoří jen jednou v životním cyklu daného scopu.
    Nebo prostě kdekoliv, kde jde jen o přechodnou hodnotu, kterou použijeme a nezměníme.

    před 15 dny | odpovědět
  2. Taco #2

    avatar

    Bod 2: ‚Čtenáře to ruší! Vidí v kódu const a ptá se: „Proč je tohle konstanta? Je to nějaká důležitá hodnota? Má to nějaký význam?“‘
    Takto čtenář uvažovat nebude. Bude uvažovat: „ha, konstanta, nebude se mi to měnit, super“

    Bod 3: ‚„Můžu změnit const na let? Nespoléhá na to někdo?“‘
    Odpověď je jednoduchá, ano, vždycky můžeš změnit const na let, a nikdo na to nikdy nespoléhá.

    Já jsem všemi deseti pro to, aby člověk přemýšlel u pojmenovávání a voleb konstrukcí. Ale uvedená kritika používání const a let mi přijde poněkud podezřelá.

    před 9 dny | odpovědět

Napište komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--

phpFashion © 2004, 2025 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.