Der Bereich ist eines der wichtigsten Konzepte in JavaScript. Wenn Sie JavaScript gut erlernen möchten, müssen Sie verstehen, wie der JavaScript-Bereich und die Bereichsketten funktionieren. Der heutige Artikel bietet eine kurze Einführung in den JavaScript-Bereich und die Bereichskette und hofft, jedem dabei zu helfen, JavaScript besser zu lernen.
JavaScript-Bereich
In jeder Programmiersprache gibt es das Konzept des Geltungsbereichs. Der Geltungsbereich ist also der zugängliche Bereich von Variablen und Funktionen. Das heißt, der Geltungsbereich steuert die Sichtbarkeit und den Lebenszyklus von Variablen und Funktionen. In JavaScript gibt es zwei Arten von Variablenbereichen: den globalen Bereich und den lokalen Bereich.
1. Globaler Geltungsbereich
Objekte, auf die überall im Code zugegriffen werden kann, haben einen globalen Gültigkeitsbereich. Im Allgemeinen haben die folgenden Situationen einen globalen Gültigkeitsbereich:
(1) Die äußerste Funktion und die außerhalb der äußersten Funktion definierten Variablen haben einen globalen Gültigkeitsbereich, zum Beispiel:
Kopieren Sie den Codecode wie folgt:
varauthorName="Mountainside Stream";
functiondoSomething(){
varblogName="";
functioninnerSay(){
Alert(BlogName);
}
innerSay();
}
Alert(authorName);//Mountainside Creek
alarm(blogName);//Skriptfehler
doSomething();//
innerSay()//Skriptfehler
(2) Alle Variablen, die nicht definiert und direkt zugewiesen sind, werden automatisch mit globalem Gültigkeitsbereich deklariert, zum Beispiel:
Kopieren Sie den Codecode wie folgt:
functiondoSomething(){
varauthorName="Mountainside Stream";
blogName="";
Alert(Autorenname);
}
alarm(blogName);//
warning(authorName);//Skriptfehler
Die Variable „blogName“ hat einen globalen Gültigkeitsbereich, aber auf „authorName“ kann außerhalb der Funktion nicht zugegriffen werden.
(3) Alle Eigenschaften von Fensterobjekten haben globalen Gültigkeitsbereich
Im Allgemeinen haben die integrierten Eigenschaften des Fensterobjekts einen globalen Geltungsbereich, z. B. window.name, window.location, window.top usw.
2. Lokaler Geltungsbereich
Im Gegensatz zum globalen Bereich kann auf den lokalen Bereich im Allgemeinen nur innerhalb eines festen Codeabschnitts zugegriffen werden, am häufigsten innerhalb einer Funktion. Daher wird dieser Bereich an manchen Stellen auch als Funktionsbereich bezeichnet, z. B. im folgenden Code: Beide blogName und Funktion innerSay haben nur einen lokalen Gültigkeitsbereich.
Kopieren Sie den Codecode wie folgt:
functiondoSomething(){
varblogName="";
functioninnerSay(){
Alert(BlogName);
}
innerSay();
}
alarm(blogName);//Skriptfehler
innerSay();//Skriptfehler
Zielfernrohrkette
In JavaScript sind Funktionen auch Objekte. Tatsächlich ist alles in JavaScript ein Objekt. Funktionsobjekte verfügen wie andere Objekte über Eigenschaften, auf die über Code zugegriffen werden kann, sowie über eine Reihe interner Eigenschaften, auf die nur die JavaScript-Engine zugreifen kann. Eine der internen Eigenschaften ist [[Scope]], definiert durch die dritte Ausgabe des ECMA-262-Standards. Diese interne Eigenschaft enthält die Sammlung von Objekten in dem Bereich, in dem die Funktion erstellt wird , die bestimmt, auf welche Daten die Funktion zugreifen kann.
Wenn eine Funktion erstellt wird, wird ihre Bereichskette mit Datenobjekten gefüllt, auf die über den Bereich zugegriffen werden kann, in dem die Funktion erstellt wurde. Definieren Sie beispielsweise die folgende Funktion:
Kopieren Sie den Codecode wie folgt:
functionadd(num1,num2){
varsum=num1+num2;
Rückgabesumme;
}
Wenn die Funktion add erstellt wird, wird ihre Gültigkeitskette mit einem globalen Objekt gefüllt, das alle globalen Variablen enthält, wie in der folgenden Abbildung dargestellt (Hinweis: Das Bild zeigt nur einen Teil aller Variablen):
Der Umfang der Funktion add wird während der Ausführung verwendet. Führen Sie beispielsweise den folgenden Code aus:
Kopieren Sie den Codecode wie folgt:
var total = add(5,10);
Wenn diese Funktion ausgeführt wird, wird ein internes Objekt namens „Ausführungskontext“ erstellt. Der Laufzeitkontext definiert die Umgebung, in der die Funktion ausgeführt wird. Jeder Laufzeitkontext verfügt über eine eigene Bereichskette zur Bezeichnerauflösung. Wenn ein Laufzeitkontext erstellt wird, wird seine Bereichskette auf das Objekt initialisiert, das in [[Scope]] der aktuell ausgeführten Funktion enthalten ist.
Die Werte werden in der Reihenfolge, in der sie in der Funktion erscheinen, in die Bereichskette des Laufzeitkontexts kopiert. Zusammen bilden sie ein neues Objekt, das als „Aktivierungsobjekt“ bezeichnet wird. Dieses Objekt enthält alle lokalen Variablen, benannten Parameter, Parametersammlungen und diese der Funktion. Anschließend wird dieses Objekt an das vordere Ende der Bereichskette verschoben zerstört wird, wird auch das aktive Objekt zerstört. Die neue Bereichskette ist unten dargestellt:
Wenn während der Ausführung der Funktion keine Variable angetroffen wird, durchläuft sie einen Identifier-Auflösungsprozess, um zu bestimmen, wo die Daten abgerufen und gespeichert werden sollen. Dieser Prozess beginnt am Kopf der Bereichskette, also beim aktiven Objekt, und sucht nach einem Bezeichner mit demselben Namen. Wenn er gefunden wird, verwenden Sie die diesem Bezeichner entsprechende Variable. Wenn er nicht gefunden wird, fahren Sie fort Suche nach dem nächsten Objekt in der Bereichskette. Wenn nach der Suche keine Objekte gefunden werden, gilt der Bezeichner als undefiniert. Während der Funktionsausführung durchläuft jeder Bezeichner einen solchen Suchvorgang.
Bereichsverkettung und Codeoptimierung
Aus der Struktur der Scope-Kette ist ersichtlich, dass die Lese- und Schreibgeschwindigkeit umso langsamer ist, je tiefer der Bezeichner in der Scope-Kette des Laufzeitkontexts liegt. Wie in der Abbildung oben gezeigt, ist das Auffinden globaler Variablen während der Identifikatorauflösung am langsamsten, da globale Variablen immer am Ende der Laufzeitkontextbereichskette vorhanden sind. Daher sollten Sie beim Schreiben von Code so wenig wie möglich globale Variablen und so viel wie möglich lokale Variablen verwenden. Eine gute Faustregel lautet: Wenn auf ein bereichsübergreifendes Objekt mehr als einmal verwiesen wird, speichern Sie es in einer lokalen Variablen, bevor Sie es verwenden. Zum Beispiel der folgende Code:
Kopieren Sie den Codecode wie folgt:
functionchangeColor(){
document.getElementById("btnChange").onclick=function(){
document.getElementById("targetCanvas").style.backgroundColor="red";
};
}
Diese Funktion referenziert das globale Variablendokument zweimal. Um die Variable zu finden, müssen Sie die gesamte Bereichskette durchlaufen, bis sie schließlich im globalen Objekt gefunden wird. Dieser Code kann wie folgt umgeschrieben werden:
Kopieren Sie den Codecode wie folgt:
functionchangeColor(){
vardoc=Dokument;
doc.getElementById("btnChange").onclick=function(){
doc.getElementById("targetCanvas").style.backgroundColor="red";
};
}
Dieser Code ist relativ einfach und zeigt nach dem Umschreiben keine große Leistungsverbesserung. Wenn das Programm jedoch eine große Anzahl globaler Variablen enthält, auf die wiederholt zugegriffen wird, wird die Leistung des umgeschriebenen Codes erheblich verbessert.
Bereichskette ändern
Der entsprechende Laufzeitkontext ist bei jeder Ausführung einer Funktion eindeutig. Daher führt der mehrmalige Aufruf derselben Funktion zur Erstellung mehrerer Laufzeitkontexte. Wenn die Ausführung der Funktion abgeschlossen ist, wird der Ausführungskontext zerstört. Jeder Laufzeitkontext ist einer Bereichskette zugeordnet. Unter normalen Umständen wird während der Ausführung des Laufzeitkontexts seine Bereichskette nur von der with-Anweisung und der Catch-Anweisung beeinflusst.
Die with-Anweisung ist eine Abkürzung für die Verwendung von Objekten, um das Schreiben wiederholten Codes zu vermeiden. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
functioninitUI(){
mit(Dokument){
varbd=Körper,
links=getElementsByTagName("a"),
ich=0,
len=links.length;
while(i<len){
update(links[i++]);
}
getElementById("btnInit").onclick=function(){
doSomething();
};
}
}
Die width-Anweisung wird hier verwendet, um zu vermeiden, dass das Dokument mehrmals geschrieben wird, was effizienter erscheint, aber tatsächlich zu Leistungsproblemen führt.
Wenn der Code die with-Anweisung erreicht, wird die Bereichskette des Laufzeitkontexts vorübergehend geändert. Es wird ein neues veränderbares Objekt erstellt, das alle Eigenschaften des durch den Parameter angegebenen Objekts enthält. Dieses Objekt wird an die Spitze der Bereichskette verschoben, was bedeutet, dass sich alle lokalen Variablen der Funktion jetzt im zweiten Bereichskettenobjekt befinden und der Zugriff daher teurer ist. Wie unten gezeigt:
Daher sollten Sie die Verwendung der with-Anweisung in Ihrem Programm vermeiden. In diesem Beispiel kann die einfache Speicherung des Dokuments in einer lokalen Variablen die Leistung verbessern.
Eine weitere Sache, die die Bereichskette ändert, ist die Catch-Anweisung in der Try-Catch-Anweisung. Wenn im Try-Codeblock ein Fehler auftritt, springt der Ausführungsprozess zur Catch-Anweisung, und dann wird das Ausnahmeobjekt in ein veränderbares Objekt verschoben und an der Spitze des Bereichs platziert. Innerhalb des Catch-Blocks werden alle lokalen Variablen der Funktion im zweiten Scope-Chain-Objekt platziert. Beispielcode:
Kopieren Sie den Codecode wie folgt:
versuchen{
doSomething();
}catch(ex){
Alert(ex.message);//Die Bereichskette ändert sich hier
}
Bitte beachten Sie, dass die Bereichskette nach Ausführung der Catch-Anweisung in ihren vorherigen Zustand zurückkehrt. Die Try-Catch-Anweisung ist beim Code-Debuggen und bei der Ausnahmebehandlung sehr nützlich, daher wird nicht empfohlen, sie vollständig zu vermeiden. Sie können die Auswirkungen von Catch-Anweisungen auf die Leistung reduzieren, indem Sie Ihren Code optimieren. Ein gutes Muster besteht darin, die Fehlerbehandlung an eine Funktion zu delegieren, zum Beispiel:
Kopieren Sie den Codecode wie folgt:
versuchen{
doSomething();
}catch(ex){
handleError(ex);//An die Prozessormethode delegieren
}
Im optimierten Code ist die handleError-Methode der einzige Code, der in der Catch-Klausel ausgeführt wird. Diese Funktion erhält als Parameter ein Ausnahmeobjekt, sodass Sie Fehler flexibler und einheitlicher behandeln können. Da nur eine Anweisung ausgeführt wird und auf keine lokalen Variablen zugegriffen wird, haben vorübergehende Änderungen in der Bereichskette keinen Einfluss auf die Codeleistung.