Stará var

Tento článek slouží k pochopení starých skriptů

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é:

  1. let
  2. const
  3. 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:

  1. Deklarace proměnné var
  2. 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 :

  1. var proměnné nemají rozsah bloku, jejich viditelnost je omezena na aktuální funkci nebo globální, pokud je deklarována mimo funkci.
  2. 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.