Das Wort "Grube" bedeutet "Falle". Aufgrund der Natur von JavaScripts "schwacher Sprache" ist es während des Gebrauchs extrem locker und flexibel, aber es ist auch extrem einfach, "getroffen" zu werden. Diese Gruben sind oft versteckt, sodass Sie die Augen offen halten müssen, um auf der Straße des Lernens und Anwendens von JS zu segeln.
1. Globale Variablen
JavaScript verwaltet Scopes durch Funktionen. In einer Funktion deklarierte Variablen befinden sich nur innerhalb dieser Funktion und sind außerhalb der Funktion nicht verfügbar. Andererseits werden globale Variablen außerhalb jeder Funktion deklariert oder einfach und einfach ohne Erklärung verwendet.
"Verwenden Sie es einfach ohne zu deklarieren" bedeutet, dass Variablen ohne Verwendung des VAR -Schlüsselworts deklariert werden. Wir haben bereits klargestellt, dass der Weg, um globale Variablen implizit zu vermeiden, darin besteht, Variablen so weit wie möglich mit dem VAR -Schlüsselwort zu deklarieren.
Aber denkst du, es ist in Ordnung, Var zu verwenden? Schauen wir uns diese Grube an:
Die Codekopie lautet wie folgt:
Funktion foo () {
var a = b = 0;
// Körper...
}
Vielleicht erwarten Sie zwei lokale Variablen, aber B ist eine echte globale Variable. Warum? Da die Zuordnungsoperation von rechts nach links ist, entspricht dies zu:
Die Codekopie lautet wie folgt:
Funktion foo () {
var a = (b = 0);
// Körper...
}
B ist also eine globale Variable.
Füllen Sie die Grube aus: variable Erklärungen, es ist am besten, einzeln zu kommen. Machen Sie keinen Großhandel ~ _ ~;
2. Variable Deklaration
Schauen wir uns zuerst die Grube an:
Die Codekopie lautet wie folgt:
myName = "global";
Funktion foo () {
Alarm (MyName);
var myname = "local";
Alarm (MyName);
}
foo ();
Auf den ersten Blick erwarten wir, dass die Ergebnisse von zwei Benachrichtigungen "global" bzw. "lokal" sind, aber die tatsächlichen Ergebnisse sind "undefiniert" und "lokal". Warum? Weil Variablen in demselben Bereich deklariert werden (gleiche Funktion) und zunächst von der Oberseite des Bereichs analysiert werden.
Das Ausführungsverhalten des oben genannten Code -Snippets könnte also so aussehen:
Die Codekopie lautet wie folgt:
Funktion foo () {
var myname;
Alarm (MyName); // "undefiniert"
myName = "local";
Alarm (MyName); // "lokal"
}
Verwenden Sie eine andere Grube, um zu testen, ob Sie die Vorbekämpfung wirklich verstehen:
Die Codekopie lautet wie folgt:
if (! ("a" im Fenster)) {
var a = 1;
}
Alarm (a);
Die Erklärung einer Variablen wird an die Spitze des Codes vorgebracht und wurde noch nicht zugewiesen. Geben Sie als nächstes die IF -Erklärung ein und beurteilen Sie, dass das "a" im Fenster festgelegt wird (a wurde als globale Variable deklariert), sodass das Ergebnis der Beurteilungsrechnung falsch ist und die IF -Aussage herausstericht, sodass der Wert von A nicht definiert ist.
Die Codekopie lautet wie folgt:
var a; // "undefiniert"
console.log ("a" im Fenster); // WAHR
if (! ("a" im Fenster)) {
var a = 1; // nicht ausgeführt
}
Alarm (a); // "undefiniert"
Füllen Sie die Grube aus: Es ist am besten, die variable Deklaration manuell an die Spitze des Geltungsbereichs zu platzieren. Für Variablen, die im Moment nicht zugewiesen werden können, können Sie die Methode zur Erklärung zuerst und dann Werte verwenden.
3. Funktionserklärung
Funktionserklärungen werden ebenfalls an die Spitze des Geltungsbereichs vorgebracht und analysiert und bewertet, bevor alle Ausdrücke und Aussagen analysiert und bewertet werden.
Die Codekopie lautet wie folgt:
alarm (typeof foo); // "Funktion"
Funktion foo () {
// Körper...
}
Sie können es vergleichen:
Die Codekopie lautet wie folgt:
alarm (typeof foo); // "undefiniert"
var foo = function () {
// Körper...
};
Wenn Sie dieses Prinzip verstehen, werden Sie dann immer noch in die folgenden Fallstricke fallen?
Die Codekopie lautet wie folgt:
Funktionstest () {
Alert ("1");
}
prüfen();
Funktionstest () {
alarm ("2");
}
prüfen();
Wenn Sie das obige Code-Snippet ausführen, sind die Popup-Fenster, die Sie sehen, "2". Warum sind sie nicht "1" bzw. "2"? Es ist sehr einfach, die Testerklärung wird vor dem Test () analysiert. Da letztere das erstere außer Kraft setzen, ist das Ergebnis beider Hinrichtungen "2".
Füllen Sie die Grube aus: In den meisten Fällen verwende ich Funktionsausdrücke anstelle von Funktionserklärungen, insbesondere in einigen Anweisungsblöcken.
4. Funktionsausdrücke
Schauen wir uns zuerst den benannten Funktionsausdruck an. Natürlich muss es zum Beispiel einen Namen geben:
Kopieren Sie den Code wie folgt: var bar = function foo () {
// Körper...
};
Es ist zu beachten, dass der Funktionsname nur für seine Funktion im Inneren sichtbar ist. Wie die folgenden Fallstricke:
Die Codekopie lautet wie folgt:
var bar bar = function foo () {
foo (); // normal laufen
};
foo (); // Fehler: ReferenzError
Füllen Sie die Grube aus: Versuchen Sie, so wenig wie möglich mit den benannten Funktionsausdrücken (mit Ausnahme einiger Rekursions- und Debugging -Zwecke) zu verwenden, und verwenden Sie die Funktionsnamen niemals extern.
5. Funktions Selbstausführung
Für Funktionsausdrücke können Sie anschließend durch addieren () ausgeführt werden, und Parameter können in Klammern übergeben werden, während die Funktionserklärung nicht kann. Grube:
Die Codekopie lautet wie folgt:
// (1) Dies ist nur ein Gruppierungsoperator, kein Funktionsaufruf!
// Die Funktion hier wurde also nicht ausgeführt, es ist immer noch eine Aussage
Funktion foo (x) {
Alarm (x);
} (1);
Die folgenden Codeausschnitte werden separat ausgeführt und das Popup-Fenster zeigt "1". Denn vor (1) sind sie Funktionsausdrücke, sodass der () hier kein Gruppierungsbetreiber, sondern ein Bediener ist, der die Anrufausführung angibt.
Kopieren Sie den Code wie folgt: // Standard anonyme Funktionsausdruck
var bar bar = function foo (x) {
Alarm (x);
} (1);
// Die vorherige () konvertiert die Funktionserklärung in einen Ausdruck
(Funktion foo (x) {
Alarm (x);
}) (1);
// der gesamte () ist ein Ausdruck
(Funktion foo (x) {
Alarm (x);
} (1));
// neuer Ausdruck
Neue Funktion foo (x) {
Alarm (x);
} (1);
// &&, ||,!, +, -, ~ usw. Betreiber (und Kommas), um Funktionsausdrücke und Funktionserklärungen zu disamsambiguieren
// Sobald der Parser weiß, dass einer von ihnen ein Ausdruck ist, werden die anderen ebenfalls standardmäßig ausdrückt.
true && function foo (x) {
Alarm (x);
} (1);
Füllen Sie die Grube: Der Schlüssel zu dieser Grube besteht darin, die Essenz aller Arten von Funktionsausdrücken herauszufinden.
6. Schließung in der Schleife
Das Folgende zeigt eine gemeinsame Gefahr:
Die Codekopie lautet wie folgt:
<! docType html>
<html lang = "en">
<kopf>
<meta charset = "utf-8">
<title> document </title>
</head>
<body>
<h3> Zeigen Sie beim Klicken auf Links unten die Anzahl seiner Sequenz </h3> an
<ul>
<li> <a href = " #"> Link #0 </a> </li>
<li> <a href = " #"> Link #1 </a> </li>
<li> <a href = " #"> Link #2 </a> </li>
<li> <a href = " #"> Link #3 </a> </li>
<li> <a href = " #"> Link #4 </a> </li>
</ul>
</body>
</html>
Die Codekopie lautet wie folgt:
var links = document.getElementsByTagName ("ul") [0] .GetElementsByTagName ("a");
für (var i = 0, l = links.length; i <l; i ++) {
Links [i] .onclick = function (e) {
E.PreventDefault ();
alert ("Sie klicken auf Link #" + i);
}
}
Wir erwarten, dass wir beim Klicken auf den I-Th-Link den Wert des Index I in dieser Sequenz erhalten. Unabhängig davon, auf welcher Link geklickt wird, erhalten wir das Endergebnis von I nach der Schleife: "5".
Erklären Sie den Grund: Wenn die Warnung aufgerufen wird, behält der Ausdruck der anonymen Funktion in der für Schleife einen Verweis auf die externe Variable I (Verschluss) bei. Zu diesem Zeitpunkt ist die Schleife beendet und der Wert von I wird auf "5" modifiziert.
Füllen Sie die Grube aus: Um das gewünschte Ergebnis zu erzielen, müssen Sie in jeder Schleife eine Kopie der Variablen I erstellen. Das Folgende zeigt den richtigen Ansatz:
Die Codekopie lautet wie folgt:
<kopf>
<meta charset = "utf-8">
<title> document </title>
</head>
<body>
<h3> Zeigen Sie beim Klicken auf Links unten die Anzahl seiner Sequenz </h3> an
<ul>
<li> <a href = " #"> Link #0 </a> </li>
<li> <a href = " #"> Link #1 </a> </li>
<li> <a href = " #"> Link #2 </a> </li>
<li> <a href = " #"> Link #3 </a> </li>
<li> <a href = " #"> Link #4 </a> </li>
</ul>
</body>
</html>
Die Codekopie lautet wie folgt:
var links = document.getElementsByTagName ("ul") [0] .GetElementsByTagName ("a");
für (var i = 0, l = links.length; i <l; i ++) {
Links [i] .onclick = (Funktion (index) {
Rückgabefunktion (e) {
E.PreventDefault ();
alert ("Sie klicken auf Link #" + Index);
}
})(ich);
}
Wie Sie sehen können, ist die Form von (function () {...}) () die Selbstaussetzung der oben genannten Funktion. Ich werde als Parameter an den Index übergeben. Wenn Alert erneut ausgeführt wird, gibt es einen Verweis auf den Index. Zu diesem Zeitpunkt wird dieser Wert nicht durch die Schleife geändert. Natürlich können Sie nach dem Verständnis des Prinzips auch so schreiben:
Die Codekopie lautet wie folgt:
für (var i = 0, l = links.length; i <l; i ++) {
(Funktion (Index) {
Links [i] .onclick = function (e) {
E.PreventDefault ();
alert ("Sie klicken auf Link #" + Index);
}
})(ich);
}
Es funktioniert auch.