Informace v tomto článku jsou užitečné pro pochopení starých skriptů.
Takto nový kód nepíšeme.
Hned v první kapitole o proměnných jsme zmínili tři způsoby deklarace proměnné:
let
const
var
var
deklarace je podobná let
. Většinu času můžeme nahradit let
podle var
nebo naopak a očekávejte, že věci budou fungovat:
var message = "Hi";
alert(message); // Hi
Ale interně var
je velmi odlišné zvíře, které pochází z velmi starých časů. Obecně se nepoužívá v moderních skriptech, ale stále se skrývá ve starých.
Pokud se s takovými skripty neplánujete setkat, můžete tuto kapitolu dokonce přeskočit nebo ji odložit.
Na druhou stranu je důležité pochopit rozdíly při migraci starých skriptů z var
na let
, abyste se vyhnuli zvláštním chybám.
„var“ nemá rozsah bloku
Proměnné deklarované pomocí var
, jsou buď s rozsahem funkcí, nebo s globálním rozsahem. Jsou viditelné skrz bloky.
Například:
if (true) {
var test = true; // use "var" instead of "let"
}
alert(test); // true, the variable lives after if
Jako var
ignoruje bloky kódu, máme globální proměnnou test
.
Pokud bychom použili let test
místo var test
, pak by proměnná byla viditelná pouze uvnitř if
:
if (true) {
let test = true; // use "let"
}
alert(test); // ReferenceError: test is not defined
Totéž pro smyčky:var
nemůže být blokově nebo ve smyčce místní:
for (var i = 0; i < 10; i++) {
var one = 1;
// ...
}
alert(i); // 10, "i" is visible after loop, it's a global variable
alert(one); // 1, "one" is visible after loop, it's a global variable
Pokud je blok kódu uvnitř funkce, pak var
se stane proměnnou na úrovni funkce:
function sayHi() {
if (true) {
var phrase = "Hello";
}
alert(phrase); // works
}
sayHi();
alert(phrase); // ReferenceError: phrase is not defined
Jak vidíme, var
prorazí přes if
, for
nebo jiné bloky kódu. Je to proto, že před dlouhou dobou v JavaScriptu bloky neměly žádná lexikální prostředí a var
je pozůstatkem toho.
„var“ toleruje opětovné deklarace
Pokud stejnou proměnnou deklarujeme pomocí let
dvakrát ve stejném rozsahu, to je chyba:
let user;
let user; // SyntaxError: 'user' has already been declared
S var
, můžeme proměnnou opakovaně deklarovat kolikrát. Pokud použijeme var
s již deklarovanou proměnnou je prostě ignorována:
var user = "Pete";
var user = "John"; // this "var" does nothing (already declared)
// ...it doesn't trigger an error
alert(user); // John
Proměnné „var“ lze deklarovat pod jejich použitím
var
deklarace jsou zpracovány při spuštění funkce (nebo spuštění skriptu pro globals).
Jinými slovy var
proměnné jsou definovány od začátku funkce, bez ohledu na to, kde je definice (za předpokladu, že definice není ve vnořené funkci).
Takže tento kód:
function sayHi() {
phrase = "Hello";
alert(phrase);
var phrase;
}
sayHi();
…Je to technicky stejné jako toto (přesunuto var phrase
výše):
function sayHi() {
var phrase;
phrase = "Hello";
alert(phrase);
}
sayHi();
…Nebo i takto (pamatujte, že bloky kódu jsou ignorovány):
function sayHi() {
phrase = "Hello"; // (*)
if (false) {
var phrase;
}
alert(phrase);
}
sayHi();
Lidé také nazývají takové chování „hoisting“ (zvedání), protože všechny var
jsou „vyzvednuty“ (zvednuty) do horní části funkce.
Takže ve výše uvedeném příkladu if (false)
větev se nikdy nespustí, ale na tom nezáleží. var
uvnitř je zpracován na začátku funkce, tedy v okamžiku (*)
proměnná existuje.
Deklarace jsou zvednuté, ale úkoly nikoli.
Nejlépe to lze demonstrovat na příkladu:
function sayHi() {
alert(phrase);
var phrase = "Hello";
}
sayHi();
Řádek var phrase = "Hello"
obsahuje dvě akce:
- Deklarace proměnné
var
- Přiřazení proměnné
=
.
Deklarace je zpracována na začátku provádění funkce („hoisted“), ale přiřazení vždy funguje na místě, kde se objeví. Takže kód funguje v podstatě takto:
function sayHi() {
var phrase; // declaration works at the start...
alert(phrase); // undefined
phrase = "Hello"; // ...assignment - when the execution reaches it.
}
sayHi();
Protože všechny var
deklarace jsou zpracovávány při startu funkce, můžeme na ně odkazovat kdekoli. Ale proměnné jsou nedefinované až do přiřazení.
V obou výše uvedených příkladech alert
běží bez chyby, protože proměnná phrase
existuje. Ale jeho hodnota ještě není přiřazena, takže ukazuje undefined
.
IIFE
V minulosti, protože existoval pouze var
a nemá žádnou viditelnost na úrovni bloku, programátoři vynalezli způsob, jak jej emulovat. To, co udělali, se nazývalo „okamžitě vyvolané funkční výrazy“ (zkráceně IIFE).
To není něco, co bychom dnes měli používat, ale můžete je najít ve starých skriptech.
IIFE vypadá takto:
(function() {
var message = "Hello";
alert(message); // Hello
})();
Zde se vytvoří a okamžitě volá funkční výraz. Kód se tedy provede okamžitě a má své vlastní soukromé proměnné.
Funkční výraz je zabalen do závorek (function {...})
, protože když stroj JavaScript narazí na "function"
v hlavním kódu to chápe jako začátek deklarace funkce. Ale deklarace funkce musí mít název, takže tento druh kódu zobrazí chybu:
// Tries to declare and immediately call a function
function() { // <-- SyntaxError: Function statements require a function name
var message = "Hello";
alert(message); // Hello
}();
I když řekneme:„Dobře, pojďme přidat jméno“, nebude to fungovat, protože JavaScript neumožňuje okamžité volání deklarací funkcí:
// syntax error because of parentheses below
function go() {
}(); // <-- can't call Function Declaration immediately
Závorky kolem funkce jsou tedy trikem, který JavaScriptu ukazuje, že funkce je vytvořena v kontextu jiného výrazu, a proto je to výraz funkce:nepotřebuje žádné jméno a lze jej volat okamžitě.
Kromě závorek existují i jiné způsoby, jak sdělit JavaScriptu, že máme na mysli výraz funkce:
// Ways to create IIFE
(function() {
alert("Parentheses around the function");
})();
(function() {
alert("Parentheses around the whole thing");
}());
!function() {
alert("Bitwise NOT operator starts the expression");
}();
+function() {
alert("Unary plus starts the expression");
}();
Ve všech výše uvedených případech deklarujeme funkční výraz a okamžitě jej spustíme. Poznamenejme znovu:v dnešní době není důvod psát takový kód.
Shrnutí
var
má dva hlavní rozdíly ve srovnání s let/const
:
var
proměnné nemají rozsah bloku, jejich viditelnost je omezena na aktuální funkci nebo globální, pokud je deklarována mimo funkci.var
deklarace jsou zpracovány při spuštění funkce (spuštění skriptu pro globals).
Existuje ještě jeden velmi malý rozdíl související s globálním objektem, kterému se budeme věnovat v další kapitole.
Tyto rozdíly činí var
horší než let
většinu času. Proměnné na úrovni bloku jsou skvělá věc. Proto let
byl zaveden ve standardu již dávno a nyní je hlavním způsobem (spolu s const
) deklarovat proměnnou.