Was ist das Ergebnis des folgenden Programms?
Kopieren Sie den Codecode wie folgt:
var foo = 1;
Funktion bar() {
if (!foo) {
var foo = 10;
}
alarm(foo);
}
Bar();
Das Ergebnis ist 10;
Was ist mit diesem hier?
Kopieren Sie den Codecode wie folgt:
var a = 1;
Funktion b() {
a = 10;
zurückkehren;
Funktion a() {}
}
B();
Warnung(a);
Das Ergebnis ist 1.
Macht es dir Angst? Was ist passiert? Das mag seltsam, gefährlich und verwirrend sein, aber es ist tatsächlich auch eine sehr nützliche und beeindruckende Funktion der JavaScript-Sprache. Ich weiß nicht, ob es für dieses Verhalten einen Standardnamen gibt, aber mir gefällt dieser Begriff: „Heben“. Dieser Artikel gibt eine einführende Erklärung dieses Mechanismus, aber zunächst müssen wir uns mit dem Umfang von JavaScript vertraut machen.
Umfang von Javascript
Für Javascript-Anfänger ist der Umfang einer der verwirrendsten Bereiche; das betrifft tatsächlich nicht nur Anfänger. Ich habe einige erfahrene JavaScript-Programmierer getroffen, aber sie verstehen den Umfang nicht genau. Der Grund, warum der JavaScript-Bereich verwirrend ist, liegt darin, dass die Programmsyntax selbst wie eine Sprache der C-Familie aussieht, wie das folgende C-Programm:
Kopieren Sie den Codecode wie folgt:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
wenn (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d/n", x);
}
Das Ausgabeergebnis ist 1 2 1. Dies liegt daran, dass die Sprachen der C-Familie einen Blockbereich haben. Wenn die Programmsteuerung in einen Block eintritt, z. B. einen if-Block, können Variablen deklariert werden, die sich nur auf den Block auswirken, ohne die Auswirkungen außerhalb des Blocks zu beeinflussen. Domain. Aber in Javascript funktioniert das nicht. Schauen Sie sich den folgenden Code an:
Kopieren Sie den Codecode wie folgt:
var x = 1;
console.log(x); // 1
if (wahr) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
Das Ergebnis wird 1 2 2 sein. Weil Javascript Funktionsumfang ist. Dies ist der größte Unterschied zur C-Sprachfamilie. Das if in diesem Programm erstellt keinen neuen Bereich.
Für viele C-, C++- und Java-Programmierer ist dies nicht das, was sie erwarten und begrüßen. Glücklicherweise gibt es aufgrund der Flexibilität von JavaScript-Funktionen Möglichkeiten, dies zu umgehen. Wenn Sie einen temporären Bereich erstellen müssen, gehen Sie etwa so vor:
Kopieren Sie den Codecode wie folgt:
Funktion foo() {
var x = 1;
wenn (x) {
(Funktion () {
var x = 2;
// ein anderer Code
}());
}
// x ist immer noch 1.
}
Diese Methode ist flexibel und kann überall dort eingesetzt werden, wo Sie einen temporären Bereich erstellen möchten. Nicht nur innerhalb des Blocks. Ich empfehle Ihnen jedoch dringend, sich die Zeit zu nehmen, den JavaScript-Scoping zu verstehen. Es ist sehr nützlich und eine meiner Lieblingsfunktionen von JavaScript. Wenn Sie den Umfang verstehen, ist das variable Heben für Sie sinnvoller.
Variablendeklaration, Benennung und Heraufstufung
In JavaScript gibt es vier grundlegende Möglichkeiten für Variablen, in den Gültigkeitsbereich zu gelangen:
•1 Integrierte Sprache: Alle Bereiche haben diese und Argumente (Anmerkung des Übersetzers: Nach dem Testen sind Argumente im globalen Bereich nicht sichtbar)
•2 Formale Parameter: Die formalen Parameter einer Funktion sind Teil des Funktionsumfangs;
•3 Funktionsdeklaration: in dieser Form: function foo(){};
•4 Variablendeklaration: etwa so: var foo;
Funktionsdeklarationen und Variablendeklarationen werden vom Interpreter immer stillschweigend an den Anfang des Methodenkörpers „angehoben“. Das bedeutet Code wie der folgende:
Kopieren Sie den Codecode wie folgt:
Funktion foo() {
Bar();
var x = 1;
}
wird tatsächlich interpretiert als:
Kopieren Sie den Codecode wie folgt:
Funktion foo() {
var x;
Bar();
x = 1;
}
Unabhängig davon, ob der Block, in dem die Variable definiert ist, ausgeführt werden kann. Die folgenden zwei Funktionen sind eigentlich dasselbe:
Kopieren Sie den Codecode wie folgt:
Funktion foo() {
if (falsch) {
var x = 1;
}
zurückkehren;
var y = 1;
}
Funktion foo() {
var x, y;
if (falsch) {
x = 1;
}
zurückkehren;
y = 1;
}
Beachten Sie, dass Variablenzuweisungen nicht gehisst werden, sondern nur Deklarationen. Die Funktionsdeklaration ist jedoch etwas anders und der Funktionskörper wird ebenfalls heraufgestuft. Bitte beachten Sie jedoch, dass es zwei Möglichkeiten gibt, eine Funktion zu deklarieren:
Kopieren Sie den Codecode wie folgt:
Funktionstest() {
foo(); // TypeError „foo ist keine Funktion“
bar(); // „das wird ausgeführt!“
var foo = function () { // Variable zeigt auf Funktionsausdruck
alarm("das wird nicht ausgeführt!");
}
function bar() { // Funktionsdeklarationsfunktion namens bar
alarm("dies wird ausgeführt!");
}
}
prüfen();
In diesem Beispiel werden nur funktionale Deklarationen zusammen mit dem Funktionskörper angehoben. Die Deklaration von foo wird angehoben, aber der Funktionskörper, auf den sie verweist, wird nur während der Ausführung zugewiesen.
Das Obige behandelt einige der Grundlagen des Boostings und sie scheinen nicht so verwirrend zu sein. In einigen speziellen Szenarien besteht jedoch immer noch ein gewisser Grad an Komplexität.
Variable Parsing-Reihenfolge
Das Wichtigste, was es zu beachten gilt, ist die Reihenfolge der variablen Auflösung. Erinnern Sie sich an die vier Möglichkeiten, wie die Benennung in den zuvor angegebenen Bereich gelangt? Die Reihenfolge, in der Variablen analysiert werden, entspricht der Reihenfolge, in der ich sie aufgelistet habe.
Kopieren Sie den Codecode wie folgt:
<Skript>
Funktion a(){
}
var a;
warning(a);//Drucken Sie den Funktionskörper von a aus
</script>
<Skript>
var a;
Funktion a(){
}
warning(a);//Drucken Sie den Funktionskörper von a aus
</script>
//Achten Sie jedoch auf den Unterschied zwischen den folgenden beiden Schreibmethoden:
<Skript>
var a=1;
Funktion a(){
}
warning(a);//Ausdrucken 1
</script>
<Skript>
Funktion a(){
}
var a=1;
warning(a);//Ausdrucken 1
</script>
Hier gibt es 3 Ausnahmen:
1 Die eingebauten Namensargumente verhalten sich seltsam. Es scheint, dass sie nach den formalen Funktionsparametern, aber vor der Funktionsdeklaration deklariert werden sollten. Das heißt, wenn der formale Parameter Argumente enthält, hat dieser Vorrang vor dem eingebauten. Dies ist eine sehr schlechte Funktion. Vermeiden Sie daher die Verwendung von Argumenten in formalen Parametern.
2 Das Definieren dieser Variablen an einer beliebigen Stelle führt zu einem Syntaxfehler, was eine gute Funktion ist.
3. Wenn mehrere formale Parameter den gleichen Namen haben, hat der letzte Parameter Vorrang, auch wenn sein Wert während der tatsächlichen Operation undefiniert ist;
benannte Funktion
Sie können einer Funktion einen Namen geben. Wenn ja, handelt es sich nicht um eine Funktionsdeklaration, und der angegebene Funktionsname (falls vorhanden, z. B. Spam unten, Anmerkung des Übersetzers) in der Funktionskörperdefinition wird nicht heraufgestuft, sondern ignoriert. Hier ist ein Code, der Ihnen das Verständnis erleichtert:
Kopieren Sie den Codecode wie folgt:
foo(); // TypeError „foo ist keine Funktion“
bar(); // gültig
baz(); // TypeError „baz ist keine Funktion“
spam(); // ReferenceError „Spam ist nicht definiert“
var foo = function () {}; // foo zeigt auf eine anonyme Funktion
function bar() {}; // Funktionsdeklaration
var baz = function spam() {}; // Benannte Funktion, nur baz wird gefördert, Spam wird nicht gefördert.
foo(); // gültig
bar(); // gültig
baz(); // gültig
spam(); // ReferenceError „Spam ist nicht definiert“
Wie schreibe ich Code?
Nachdem Sie nun das Scoping und das Heben von Variablen verstanden haben, was bedeutet das für die JavaScript-Codierung? Das Wichtigste ist, dass Sie Ihre Variablen immer mit var definieren. Und ich empfehle dringend, dass es für einen Namen immer nur eine var-Deklaration in einem Bereich geben sollte. Wenn Sie dies tun, treten keine Probleme mit der Reichweite und dem variablen Heben auf.
Was meinst du mit Sprachangabe?
Ich finde die ECMAScript-Referenzdokumentation immer nützlich. Folgendes habe ich zum Umfang und zum variablen Heben herausgefunden:
Wenn eine Variable in einer Funktionskörperklasse deklariert wird, handelt es sich um einen Funktionsbereich. Andernfalls ist der Gültigkeitsbereich global (als Eigenschaft von global). Variablen werden erstellt, wenn die Ausführung in den Gültigkeitsbereich eintritt. Blöcke definieren keine neuen Bereiche, nur Funktionsdeklarationen und Prozeduren (der Übersetzer geht davon aus, dass es sich um eine globale Codeausführung handelt) erstellen neue Bereiche. Variablen werden beim Erstellen auf undefiniert initialisiert. Wenn die Variablendeklarationsanweisung eine Zuweisungsoperation enthält, wird die Zuweisungsoperation nur bei ihrer Ausführung und nicht bei ihrer Erstellung ausgeführt.
Ich hoffe, dass dieser Artikel Programmierern, die in Bezug auf JavaScript verwirrt sind, einen Lichtblick bringt. Ich versuche auch mein Bestes, um nicht noch mehr Verwirrung zu stiften. Wenn ich etwas Falsches gesagt oder etwas übersehen habe, lassen Sie es mich bitte wissen.
Beilage für Übersetzer
Ein Freund erinnerte mich an das Problem der Heraufstufung benannter Funktionen im globalen Bereich unter IE:
So habe ich es getestet, als ich den Artikel übersetzt habe:
Kopieren Sie den Codecode wie folgt:
<Skript>
functiont(){
spam();
var baz = function spam() {alert('das ist Spam')};
}
T();
</script>
Diese Schreibweise, also die Förderung benannter Funktionen im nicht-globalen Bereich, hat unter ie und ff die gleiche Leistung wie:
Kopieren Sie den Codecode wie folgt:
<Skript>
spam();
var baz = function spam() {alert('das ist Spam')};
</script>
Dann kann Spam unter ie ausgeführt werden, nicht jedoch unter ff. Dies zeigt, dass verschiedene Browser dieses Detail unterschiedlich handhaben.
Diese Frage hat mich auch dazu gebracht, über zwei weitere Fragen nachzudenken: 1: Bei Variablen mit globalem Gültigkeitsbereich gibt es einen Unterschied zwischen var und nicht var. Ohne var wird die Variable nicht hochgestuft. Von den folgenden beiden Programmen meldet beispielsweise das zweite einen Fehler:
Kopieren Sie den Codecode wie folgt:
<Skript>
Warnung(a);
var a=1;
</script>
Kopieren Sie den Codecode wie folgt:
<Skript>
Warnung(a);
a=1;
</script>
2: Lokale Variablen, die in eval erstellt wurden, werden nicht hochgestuft (es gibt keine Möglichkeit, dies zu tun).
Kopieren Sie den Codecode wie folgt:
<Skript>
var a = 1;
Funktion t(){
Warnung(a);
eval('var a = 2');
Warnung(a);
}
T();
Warnung(a);
</script>