Geltungsbereich und Verschlüsse

In JavaScript ist Gültigkeitsbereich der Kontext, in dem Code ausgeführt wird. Es gibt drei Arten von Bereichen: globaler Bereich, lokaler Bereich (manchmal als "Funktionsumfang" bezeichnet) und Eval-Bereich.

Code definiert mit var Das Innere einer Funktion ist lokal begrenzt und nur für andere Ausdrücke in dieser Funktion "sichtbar", die Code in verschachtelten / untergeordneten Funktionen enthalten. Auf Variablen, die im globalen Gültigkeitsbereich definiert sind, kann von überall her zugegriffen werden, da es sich um die oberste Ebene und den letzten Stopp in der Gültigkeitsbereichskette handelt.

Untersuchen Sie den folgenden Code und stellen Sie sicher, dass Sie verstehen, dass jede Deklaration von foo ist aufgrund des Umfangs einzigartig.

Beispiel: sample110.html

 

Stellen Sie sicher, dass Sie das jeweils verstehen foo Variable enthält einen anderen Wert, da jeder in einem spezifisch abgegrenzten Bereich definiert ist.

Eine unbegrenzte Anzahl von Funktions- und Bewertungsbereichen kann erstellt werden, während eine JavaScript-Umgebung nur einen globalen Bereich verwendet.

Der globale Gültigkeitsbereich ist die letzte Station in der Gültigkeitsbereichskette.

Funktionen, die Funktionen enthalten, erstellen gestapelte Ausführungsbereiche. Diese miteinander verketteten Stapel werden oft als Scope-Chain bezeichnet.


JavaScript hat keinen Sperrbereich

Da logische Anweisungen (ob) und Schleifenanweisungen (zum) Erstellen Sie keinen Gültigkeitsbereich, die Variablen können sich überschreiben. Untersuchen Sie den folgenden Code, und stellen Sie sicher, dass Sie den Wert von kennen foo wird neu definiert, während das Programm den Code ausführt.

Beispiel: sample111.html

 

So foo ändert sich, während der Code ausgeführt wird, da JavaScript keine Blockfunktion, keinen globalen oder eval-Gültigkeitsbereich hat.


Benutzen var Innerhalb von Funktionen zum Deklarieren von Variablen und zum Vermeiden von Scope-Gotchas

JavaScript deklariert alle Variablen ohne a var Deklaration (auch die in einer Funktion oder gekapselten Funktionen enthaltenen), die sich im globalen Bereich und nicht im beabsichtigten lokalen Bereich befindet. Schauen Sie sich den folgenden Code an und beachten Sie das ohne die Verwendung von var Um den Balken zu deklarieren, ist die Variable tatsächlich im globalen Gültigkeitsbereich definiert und nicht im lokalen Gültigkeitsbereich.

Beispiel: sample112.html

 

Das Konzept zum Mitnehmen ist, dass Sie es immer verwenden sollten var beim Definieren von Variablen innerhalb einer Funktion. Dies verhindert, dass Sie mit möglicherweise verwirrenden Umfangsproblemen fertig werden. Die Ausnahme zu dieser Konvention ist natürlich, wenn Sie im globalen Bereich Eigenschaften aus einer Funktion heraus erstellen oder ändern möchten.


Die Scope-Kette (auch bekannt als Lexical Scoping)

Es gibt eine Suchkette, die folgt, wenn JavaScript nach dem mit einer Variablen verknüpften Wert sucht. Diese Kette basiert auf der Hierarchie des Bereichs. Im folgenden Code protokolliere ich den Wert von sayHiText von dem func2 Funktionsumfang.

Beispiel: sample113.html

 

Wie ist der Wert von sayHiText gefunden, wenn es nicht im Gültigkeitsbereich des enthalten ist func2 Funktion? JavaScript schaut zuerst in die func2 Funktion für eine Variable namens sayHiText. Nicht finden func2 dort sieht es auf func2s übergeordnete Funktion, func1. Das sayHiText Variable wird nicht im gefunden func1 Bereich auch, also fährt JavaScript mit dem globalen Bereich fort, wo sayHiText gefunden wird, an welcher Stelle der Wert von sayHiText geliefert wird. Ob sayHiText war im globalen Geltungsbereich nicht definiert, nicht definiert wäre von JavaScript zurückgegeben worden.

Dies ist ein sehr wichtiges Verständnis. Sehen wir uns ein weiteres Codebeispiel an, in dem wir drei Werte aus drei verschiedenen Bereichen herausgreifen.

Beispiel: sample114.html

 

Der Wert für z ist lokal für die Bar Funktion und den Kontext, in dem die console.log wird aufgerufen. Der Wert für y ist in dem foo Funktion, die übergeordnet ist Bar(), und der Wert für x ist im globalen Bereich. Alle diese sind dem zugänglich Bar Funktion über die Scope-Kette. Stellen Sie sicher, dass Sie verstehen, dass die referenzierenden Variablen im Bar Die Funktion prüft die Variablen bis hinauf in der gesamten Scope-Kette.

Wenn Sie darüber nachdenken, unterscheidet sich die Scope-Kette nicht so sehr von der Prototyp-Kette. Beides ist einfach ein Weg, um einen Wert durch Überprüfen systematischer und hierarchischer Positionen zu ermitteln.


Die Scope-Kettensuche gibt den zuerst gefundenen Wert zurück

Im folgenden Codebeispiel wird eine Variable aufgerufen x existiert in demselben Umfang, in dem es mit geprüft wird console.log. Dieser "lokale" Wert von x verwendet wird, und man könnte sagen, dass es den identisch benannten Schatten oder Masken gibt x Variablen, die weiter oben in der Scope-Kette gefunden werden.

Beispiel: sample115.html

 

Denken Sie daran, dass die Suche nach dem Gültigkeitsbereich endet, wenn die Variable im nächstgelegenen verfügbaren Link der Kette gefunden wird, auch wenn derselbe Variablenname weiter oben in der Kette verwendet wird.


Der Bereich wird während der Funktionsdefinition bestimmt, nicht beim Aufruf

Da Funktionen den Gültigkeitsbereich bestimmen und Funktionen wie ein beliebiger JavaScript-Wert weitergegeben werden können, könnte man denken, dass das Entziffern der Gültigkeitsbereichskette kompliziert ist. Es ist eigentlich sehr einfach. Die Umfangskette wird basierend auf dem Ort einer Funktion während der Definition festgelegt, nicht während des Aufrufs. Dies wird auch als lexikalisches Scoping bezeichnet. Denken Sie lange und gründlich darüber nach, da die meisten Benutzer im JavaScript-Code häufig darüber stolpern.

Die Gültigkeitsbereichskette wird erstellt, bevor Sie eine Funktion aufrufen. Aus diesem Grund können wir Verschlüsse erstellen. Beispielsweise kann eine Funktion eine verschachtelte Funktion an den globalen Gültigkeitsbereich zurückgeben, jedoch kann unsere Funktion über die Gültigkeitsbereichskette weiterhin auf den Gültigkeitsbereich der übergeordneten Funktion zugreifen. Im folgenden Beispiel definieren wir a parentFunction das gibt eine anonyme Funktion zurück, und wir rufen die zurückgegebene Funktion aus dem globalen Bereich auf. Weil unsere anonyme Funktion innerhalb von definiert wurde parentFunction, Es hat immer noch Zugriff auf parentFunctions Bereich, wenn es aufgerufen wird. Dies wird als Schließung bezeichnet.

Beispiel: sample116.html

 

Die Idee, die Sie hier mitnehmen sollten, ist, dass die Scope-Chain während der Definition wörtlich durch die Art und Weise bestimmt wird, wie der Code geschrieben wird. Durch das Weitergeben von Funktionen in Ihrem Code wird die Gültigkeitsbereichskette nicht geändert.


Verschlüsse werden durch die Scope-Kette verursacht

Nehmen Sie das, was Sie über die Umfangskette und die Suche nach Umfang in diesem Artikel gelernt haben, und eine Schließung sollte nicht übermäßig kompliziert sein. Im folgenden Beispiel erstellen wir eine Funktion namens countUpFromZero. Diese Funktion gibt tatsächlich einen Verweis auf die darin enthaltene untergeordnete Funktion zurück. Wenn diese untergeordnete Funktion (verschachtelte Funktion) aufgerufen wird, hat sie aufgrund der Bereichskette weiterhin Zugriff auf den Bereich der übergeordneten Funktion.

Beispiel: sample117.html

 

Jedes Mal die countUpFromZero Funktion aufgerufen wird, ist die anonyme Funktion im enthalten (und wird von diesem zurückgegeben) countUpFromZero Funktion hat immer noch Zugriff auf den Umfang der übergeordneten Funktion. Diese Technik, die über die Scope-Chain ermöglicht wird, ist ein Beispiel für einen Verschluss.


Fazit

Wenn Sie das Gefühl haben, ich habe zu vereinfachte Schließungen, sind Sie mit diesem Gedanken wahrscheinlich richtig. Ich tat dies jedoch absichtlich, da ich glaube, dass die wichtigen Teile aus einem soliden Verständnis der Funktionen und des Umfangs stammen, nicht notwendigerweise aus der Komplexität des Ausführungskontextes. Wenn Sie sich eingehend mit Verschlüssen befassen möchten, lesen Sie JavaScript Closures.