Dieser Artikel dient dem Verständnis alter Skripte
Die Informationen in diesem Artikel sind hilfreich, um alte Skripte zu verstehen.
So schreiben wir keinen neuen Code.
Im allerersten Kapitel über Variablen haben wir drei Möglichkeiten der Variablendeklaration erwähnt:
let
const
var
Die var
-Deklaration ähnelt let
. Meistens können wir let
durch var
oder umgekehrt ersetzen und erwarten, dass die Dinge funktionieren:
var message = "Hallo"; Warnung (Nachricht); // Hallo
Aber intern ist var
ein ganz anderes Biest, das aus sehr alten Zeiten stammt. Es wird in modernen Skripten im Allgemeinen nicht verwendet, lauert aber immer noch in den alten.
Wenn Sie nicht vorhaben, solche Skripte kennenzulernen, können Sie dieses Kapitel sogar überspringen oder verschieben.
Andererseits ist es wichtig, die Unterschiede bei der Migration alter Skripte von var
nach let
zu verstehen, um seltsame Fehler zu vermeiden.
Variablen, die mit var
deklariert werden, haben entweder einen Funktionsbereich oder einen globalen Gültigkeitsbereich. Sie sind durch Blöcke sichtbar.
Zum Beispiel:
if (wahr) { var test = true; // „var“ statt „let“ verwenden } Warnung(Test); // true, die Variable bleibt nach if bestehen
Da var
Codeblöcke ignoriert, haben wir einen globalen test
.
Wenn wir let test
anstelle von var test
verwenden würden, wäre die Variable im Inneren nur sichtbar, if
:
if (wahr) { let test = true; // „let“ verwenden } Warnung(Test); // ReferenceError: Test ist nicht definiert
Das Gleiche gilt für Schleifen: var
kann nicht block- oder schleifenlokal sein:
für (var i = 0; i < 10; i++) { var eins = 1; // ... } alarm(i); // 10, „i“ ist nach der Schleife sichtbar, es ist eine globale Variable alarm(eins); // 1, „one“ ist nach der Schleife sichtbar, es ist eine globale Variable
Wenn sich ein Codeblock innerhalb einer Funktion befindet, wird var
zu einer Variablen auf Funktionsebene:
Funktion sayHi() { if (wahr) { var Phrase = „Hallo“; } Warnung(Satz); // funktioniert } sayHi(); Warnung(Satz); // ReferenceError: Phrase ist nicht definiert
Wie wir sehen können, durchdringt var
if
, for
oder andere Codeblöcke. Das liegt daran, dass Blöcke vor langer Zeit in JavaScript keine lexikalischen Umgebungen hatten und var
ein Überbleibsel davon ist.
Wenn wir dieselbe Variable zweimal mit let
im selben Gültigkeitsbereich deklarieren, ist das ein Fehler:
Benutzer lassen; Benutzer lassen; // SyntaxError: 'user' wurde bereits deklariert
Mit var
können wir eine Variable beliebig oft neu deklarieren. Wenn wir var
mit einer bereits deklarierten Variablen verwenden, wird diese einfach ignoriert:
var user = „Pete“; var user = „John“; // diese „var“ macht nichts (bereits deklariert) // ...es löst keinen Fehler aus Warnung(Benutzer); // John
var
-Deklarationen werden verarbeitet, wenn die Funktion startet (oder das Skript für Globals startet).
Mit anderen Worten: var
-Variablen werden vom Anfang der Funktion an definiert, unabhängig davon, wo sich die Definition befindet (vorausgesetzt, die Definition befindet sich nicht in der verschachtelten Funktion).
Also dieser Code:
Funktion sayHi() { Phrase = „Hallo“; Warnung(Satz); var-Phrase; } sayHi();
…Ist technisch gesehen das Gleiche wie dies (oben verschobene var phrase
):
Funktion sayHi() { var-Phrase; Phrase = „Hallo“; Warnung(Satz); } sayHi();
…Oder auch so (denken Sie daran, Codeblöcke werden ignoriert):
Funktion sayHi() { Phrase = „Hallo“; // (*) if (falsch) { var-Phrase; } Warnung(Satz); } sayHi();
Man nennt ein solches Verhalten auch „Hoisting“ (Erhöhen), weil alle var
an die Spitze der Funktion „gehisst“ (erhöht) werden.
if (false)
Zweig nie ausgeführt wird, spielt das keine Rolle. Die darin enthaltene var
wird am Anfang der Funktion verarbeitet, sodass die Variable zum Zeitpunkt (*)
existiert.
Deklarationen werden erhoben, Zuweisungen jedoch nicht.
Das lässt sich am besten anhand eines Beispiels demonstrieren:
Funktion sayHi() { Warnung(Satz); var Phrase = „Hallo“; } sayHi();
Die Zeile var phrase = "Hello"
enthält zwei Aktionen:
Variablendeklaration var
Variablenzuweisung =
.
Die Deklaration wird zu Beginn der Funktionsausführung verarbeitet („gehievt“), die Zuweisung funktioniert jedoch immer an der Stelle, an der sie erscheint. Der Code funktioniert also im Wesentlichen so:
Funktion sayHi() { var-Phrase; // Deklaration funktioniert am Anfang... Warnung(Satz); // undefiniert Phrase = „Hallo“; // ...Zuweisung – wenn die Ausführung sie erreicht. } sayHi();
Da alle var
-Deklarationen beim Funktionsstart verarbeitet werden, können wir an jeder Stelle auf sie verweisen. Aber Variablen sind bis zu den Zuweisungen undefiniert.
In beiden obigen Beispielen wird alert
ohne Fehler ausgeführt, da die Variable phrase
vorhanden ist. Da sein Wert jedoch noch nicht zugewiesen ist, wird undefined
angezeigt.
Da es in der Vergangenheit nur var
gab und es keine Sichtbarkeit auf Blockebene gab, erfanden Programmierer eine Möglichkeit, es zu emulieren. Was sie taten, wurde „sofort aufgerufene Funktionsausdrücke“ (abgekürzt als IIFE) genannt.
Das sollten wir heutzutage nicht mehr verwenden, aber man findet sie in alten Skripten.
Ein IIFE sieht so aus:
(Funktion() { var message = "Hallo"; Warnung (Nachricht); // Hallo })();
Hier wird ein Funktionsausdruck erstellt und sofort aufgerufen. Der Code wird also sofort ausgeführt und verfügt über eigene private Variablen.
Der Funktionsausdruck wird in Klammern eingeschlossen (function {...})
, denn wenn die JavaScript-Engine im Hauptcode auf "function"
trifft, versteht sie dies als Beginn einer Funktionsdeklaration. Da eine Funktionsdeklaration jedoch einen Namen haben muss, gibt diese Art von Code einen Fehler aus:
// Versucht eine Funktion zu deklarieren und sofort aufzurufen function() { // <-- SyntaxError: Funktionsanweisungen erfordern einen Funktionsnamen var message = "Hallo"; Warnung (Nachricht); // Hallo }();
Selbst wenn wir sagen: „Okay, fügen wir einen Namen hinzu“, wird das nicht funktionieren, da JavaScript den sofortigen Aufruf von Funktionsdeklarationen nicht zulässt:
// Syntaxfehler aufgrund der Klammern unten Funktion go() { }(); // <-- Funktionsdeklaration kann nicht sofort aufgerufen werden
Die Klammern um die Funktion sind also ein Trick, um JavaScript zu zeigen, dass die Funktion im Kontext eines anderen Ausdrucks erstellt wird und es sich daher um einen Funktionsausdruck handelt: Sie benötigt keinen Namen und kann sofort aufgerufen werden.
Neben Klammern gibt es noch andere Möglichkeiten, JavaScript mitzuteilen, dass wir einen Funktionsausdruck meinen:
// Möglichkeiten, IIFE zu erstellen (Funktion() { alarm("Klammern um die Funktion"); })(); (Funktion() { alarm("Klammern um das Ganze"); }()); !function() { alarm("Bitweiser NOT-Operator startet den Ausdruck"); }(); +Funktion() { alarm("Unäres Plus startet den Ausdruck"); }();
In allen oben genannten Fällen deklarieren wir einen Funktionsausdruck und führen ihn sofort aus. Beachten wir noch einmal: Heutzutage gibt es keinen Grund mehr, solchen Code zu schreiben.
Es gibt zwei Hauptunterschiede zwischen var
und let/const
:
var
-Variablen haben keinen Blockbereich, ihre Sichtbarkeit ist auf die aktuelle Funktion beschränkt oder global, wenn sie außerhalb der Funktion deklariert wird.
var
Deklarationen werden beim Funktionsstart verarbeitet (Skriptstart für Globals).
Es gibt noch einen weiteren, sehr kleinen Unterschied im Zusammenhang mit dem globalen Objekt, den wir im nächsten Kapitel behandeln werden.
Diese Unterschiede machen var
die meiste Zeit schlechter als let
. Variablen auf Blockebene sind eine großartige Sache. Aus diesem Grund wurde let
vor langer Zeit in den Standard eingeführt und ist heute (zusammen mit const
) eine wichtige Möglichkeit, eine Variable zu deklarieren.