9. března 2025

Eval: spuštění řetězce kódu

Zabudovaná funkce eval nám umožňuje spustit řetězec kódu.

Syntaxe je:

let výsledek = eval(kód);

Například:

let kód = 'alert("Ahoj")';
eval(kód); // Ahoj

Řetězec kódu může být dlouhý, může obsahovat konce řádku, deklarace funkcí, proměnné a podobně.

Výsledkem funkce eval je výsledek posledního příkazu.

Příklad:

let hodnota = eval('1+1');
alert(hodnota); // 2
let hodnota = eval('let i = 0; ++i');
alert(hodnota); // 1

Vyhodnocovaný kód je spouštěn v aktuálním lexikálním prostředí, takže vidí vnější proměnné:

let a = 1;

function f() {
  let a = 2;

  eval('alert(a)'); // 2
}

f();

Může vnější proměnné také měnit:

let x = 5;
eval("x = 10");
alert(x); // 10, hodnota změněna

Ve striktním režimu má eval své vlastní lexikální prostředí, takže funkce a proměnné deklarované uvnitř eval nejsou viditelné zvenčí:

// pamatujte: 'use strict' je ve spustitelných příkladech standardně zapnuté

eval("let x = 5; function f() {}");

alert(typeof x); // undefined (taková proměnná neexistuje)
// funkce f rovněž není viditelná

Bez use strict nemá eval své vlastní lexikální prostředí, takže bychom x a f venku viděli.

Použití „eval“

V moderním programování se eval používá velmi vzácně. Často se říká, že „eval je zlo“ (anglicky „eval is evil“).

Důvod je jednoduchý: před dávnými, dávnými časy byl JavaScript mnohem slabší jazyk a mnoho věcí bylo možné provést jedině pomocí eval. Ale tahle doba pominula už před deseti lety.

V současnosti není téměř žádný důvod, proč eval používat. Pokud ho někdo používá, je velká šance, že ho lze nahradit nějakým moderním jazykovým konstruktem nebo JavaScriptovým modulem.

Prosíme všimněte si, že jeho schopnost přistupovat k vnějším proměnným má vedlejší efekty.

Minifikátory kódu (nástroje používané před odesláním JS do produkce, aby jej zkomprimovaly) přejmenovávají lokální proměnné na kratší (např. a, b atd.), aby kód zkrátily. To je obvykle bezpečné, ale při použití eval ne, protože vyhodnocovaný řetězec kódu může k lokálním proměnným přistupovat. Minifikátory tedy u proměnných, které mohou být viditelné z eval, toto přejmenování neprovádějí. To negativně ovlivňuje poměr komprese kódu.

Rovněž používání vnějších lokálních proměnných uvnitř eval se považuje za špatnou programátorskou praktiku, protože ztěžuje údržbu kódu.

Existují dva způsoby, jak být před takovými problémy zcela v bezpečí.

Jestliže vyhodnocovaný kód nepoužívá vnější proměnné, prosíme volejte eval jako window.eval(...):

Tímto způsobem bude kód spuštěn v globálním rozsahu platnosti:

let x = 1;
{
  let x = 5;
  window.eval('alert(x)'); // 1 (globální proměnná)
}

Jestliže vyhodnocovaný kód potřebuje lokální proměnné, změňte eval na new Function a předejte je jako argumenty:

let f = new Function('a', 'alert(a)');

f(5); // 5

Konstrukt new Function je vysvětlen v kapitole Syntaxe „new Function“. Vytvoří funkci z řetězce, rovněž v globálním rozsahu platnosti. Funkce tedy neuvidí lokální proměnné. Je však mnohem čistší předat je explicitně jako argumenty, tak jako v uvedeném příkladu.

Shrnutí

Volání eval(kód) spustí řetězec kódu a vrátí výsledek posledního příkazu.

  • V moderním JavaScriptu se používá málokdy, jelikož obvykle není zapotřebí.
  • Může přistupovat k vnějším lokálním proměnným. To se považuje za špatnou praktiku.
  • K vyhodnocení kódu v globálním rozsahu platnosti místo něj použijte window.eval(kód).
  • Nebo, jestliže váš kód potřebuje data z vnějšího rozsahu, použijte new Function a předejte je jako argumenty.

Úlohy

důležitost: 4

Vytvořte kalkulátor, který se zeptá na aritmetický výraz a vrátí jeho výsledek.

V této úloze není třeba ověřovat správnost výrazu. Jenom ho vyhodnoťte a vraťte výsledek.

Spustit demo

K výpočtu matematického výrazu použijme eval:

let výraz = prompt("Zadejte aritmetický výraz:", '2*3+2');

alert( eval(výraz) );

Uživatel však může zadat libovolný text nebo kód.

Abychom všechno zabezpečili a omezili se jen na aritmetiku, můžeme zkontrolovat výraz pomocí regulárního výrazu, aby směl obsahovat jen číslice a operátory.

Mapa tutoriálu

Komentáře

přečtěte si před komentováním…
  • Máte-li návrhy na zlepšení, vytvořte prosím issue na GitHubu nebo pull request místo komentáře.
  • Pokud v článku něčemu nerozumíte, napište prosím, čemu přesně a na kterém místě.
  • Pro vložení několika slov kódu použijte značku <code>, pro několik řádků je obalte značkou <pre>, pro více než 10 řádků vložte odkaz na pískoviště (plnkr, jsbin, codepen…)