Ich habe gerade einen großartigen Artikel über JavaScript Scoping und Hoisting von Ben Cherry gelesen, in dem er das folgende Beispiel gibt:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Mit dem obigen Code alarmiert der Browser "1".
Ich bin mir immer noch nicht sicher, warum es "1" zurückgibt. Einige der Dinge, die er sagt, kommen in den Sinn wie: Alle Funktionsdeklarationen werden nach oben gehoben. Sie können eine Variable mit der Funktion erfassen. Klickt immer noch nicht für mich.
javascript
scope
scoping
hoisting
Entwickler
quelle
quelle
var a
vor der Funktionsdeklaration und die Zuweisunga = 1
nach sein. Beachten Sie jedoch, dass dies nicht vom Parser, Tokeniser, Interpreter, Compiler angegeben wird. Es ist nur ein Äquivalent.function a() {}
sich das gleiche verhalten wievar a = function () {};
" - dies ist in zweierlei Hinsicht falsch: Erstens, wenn überhaupt, wäre es gewesenvar a = function a() {};
(die Funktion ist eigentlich nicht anonym), zweitens sind diese beiden Formen nicht austauschbar, weil vonvar a = function a() {};
nur dasvar a;
Teil wäre gehisst worden. Dera = function a() {};
Teil wäre immer noch hinter der Rückgabeerklärung gewesen. Da das ursprüngliche Formular eine Funktionsdeklaration und kein Funktionsausdruck ist, wird es tatsächlich als Ganzes hochgezogen.Was Sie beachten müssen, ist, dass es die gesamte Funktion analysiert und alle Variablendeklarationen auflöst, bevor es ausgeführt wird. So....
wird wirklich
var a
Erzwingt es in einen lokalen Bereich, und der Variablenbereich erstreckt sich über die gesamte Funktion. Die globale Variable a ist also immer noch 1, da Sie a in einen lokalen Bereich deklariert haben, indem Sie es zu einer Funktion gemacht haben.quelle
Die Funktion
a
wird innerhalb der Funktion gehisstb
:das ist fast wie mit
var
:Die Funktion wird lokal deklariert, und die Einstellung erfolgt
a
nur im lokalen Bereich, nicht im globalen var.quelle
function a(){}
wird zuerst gehisst und verhält sich wie folgtvar a = function () {};
, daher wird im lokalen Bereicha
erstellt.a=10
, legen Sie die lokale Variable festa
, nicht die globale.Daher bleibt der Wert der globalen Variablen gleich und Sie erhalten eine Warnung 1
quelle
function a() { }
ist eine Funktionsanweisung, die einea
lokale Variable für dieb
Funktion erstellt.Variablen werden erstellt, wenn eine Funktion analysiert wird, unabhängig davon, ob die
var
Anweisung oder ausgeführt wird.a = 10
setzt diese lokale Variable.quelle
a = 10
eine Variable im globalen Bereich, wenn die Funktionb
ausgeführt wird, sofern Sie nichts hinzufügen"use strict"
(in Umgebungen, die diese Anweisung unterstützen).Was ist der Streitpunkt in diesem kleinen Codeausschnitt?
Fall 1:
Fügen Sie die
function a(){}
Definitionfunction b
wie folgt in den Körper ein .logs value of a = 1
Fall 2
Schließen Sie die
function a(){}
Definition innerhalb des Körpersfunction b
wie folgt aus.logs value of a = 10
Durch Beobachtung können Sie erkennen, dass die Anweisung
console.log(a)
die folgenden Werte protokolliert.Fall 1: a = 1
Fall 2: a = 10
Posits
var a
wurde im globalen Bereich lexikalisch definiert und deklariert.a=10
Diese Anweisung weist den Wert 10 neu zu und befindet sich lexikalisch in der Funktion b.Erklärung beider Fälle
Wegen
function definition with name property
a ist das gleiche wie dasvariable a
. Dasvariable a
Innerefunction body b
wird zu einer lokalen Variablen. Die vorherige Zeile impliziert, dass der globale Wert von a intakt bleibt und der lokale Wert von a auf 10 aktualisiert wird.Wir wollen also sagen, dass der folgende Code
Es wird vom JS-Interpreter wie folgt interpretiert.
Wenn wir jedoch die entfernen
function a(){} definition
, dievalue of 'a'
erklärt und außerhalb der Funktion b definiert ist , wird dieser Wert überschrieben und es ändert sich auf 10 bei 2. Der Wert überschrieben wird , weila=10
auf die globale Erklärung bezieht , und wenn sie deklariert werden sollten lokal müssen wir haben geschriebenvar a = 10;
.Wir können unsere Zweifel weiter klären, indem wir das
name property
Infunction a(){} definition
in einen anderen Namen als ändern'a'
quelle
Heben ist ein Konzept, das für uns entwickelt wurde, um das Verständnis zu erleichtern. Was tatsächlich passiert, ist, dass die Deklarationen zuerst in Bezug auf ihren Geltungsbereich erfolgen und die Zuweisungen danach erfolgen (nicht gleichzeitig).
Wenn die Deklarationen stattfinden,
var a
wirdfunction b
und innerhalb diesesb
Bereichsfunction a
deklariert.Diese Funktion a schattiert die Variable a aus dem globalen Bereich.
Nachdem die Deklarationen abgeschlossen sind, beginnen die zugewiesenen Werte, der globale
a
erhält den Wert1
und das a insidefunction b
wird erhalten10
. Wenn Sie dies tunalert(a)
, wird die tatsächliche globale Bereichsvariable aufgerufen. Diese kleine Änderung am Code wird es klarer machenquelle
Überraschenderweise erwähnt keine der Antworten hier die Relevanz des Ausführungskontexts in der Scope-Kette.
Die JavaScript Engine umschließt den aktuell ausgeführten Code mit einem Ausführungskontext. Der Basisausführungskontext ist der globale Ausführungskontext. Jedes Mal, wenn eine neue Funktion aufgerufen wird, wird ein neuer Ausführungskontext erstellt und auf den Ausführungsstapel gelegt. Stellen Sie sich einen Stapelrahmen vor, der in anderen Programmiersprachen auf einem Aufrufstapel sitzt. Zuletzt rein, zuerst raus. Jetzt hat jeder Ausführungskontext seine eigene variable Umgebung und äußere Umgebung in JavaScript.
Ich werde das folgende Beispiel als Demonstration verwenden.
1) Zuerst treten wir in die Erstellungsphase des globalen Ausführungskontexts ein. Sowohl die äußere als auch die variable Umgebung der lexikalischen Umgebung werden erstellt. Das globale Objekt wird eingerichtet und im Speicher abgelegt, wobei die spezielle Variable 'this' darauf zeigt. Die Funktion a und ihr Code sowie die Variable myVar mit einem undefinierten Wert werden in der globalen Variablenumgebung gespeichert. Es ist wichtig zu beachten, dass der Code der Funktion a nicht ausgeführt wird. Es wird nur mit der Funktion a gespeichert.
2) Zweitens ist es die Ausführungsphase des Ausführungskontexts. myVar ist kein undefinierter Wert mehr. Es wird mit dem Wert 1 initialisiert, der in der globalen Variablenumgebung gespeichert ist. Die Funktion a wird aufgerufen und ein neuer Ausführungskontext erstellt.
3) Im Ausführungskontext der Funktion a durchläuft sie die Erstellungs- und Ausführungsphase ihres eigenen Ausführungskontexts. Es hat eine eigene äußere Umgebung und eine variable Umgebung, also eine eigene lexikalische Umgebung. Die Funktion b und die Variable myVar werden in ihrer Variablenumgebung gespeichert. Diese variable Umgebung unterscheidet sich von der globalen variablen Umgebung. Da sich die Funktion a lexikalisch (physisch im Code) auf derselben Ebene wie der globale Ausführungskontext befindet, ist ihre äußere Umgebung der globale Ausführungskontext. Wenn sich die Funktion a auf eine Variable beziehen soll, die sich nicht in ihrer Variablenumgebung befindet, durchsucht sie die Bereichskette und versucht, die Variable in der Variablenumgebung des globalen Ausführungskontexts zu finden.
4) Die Funktion b wird in Funktion a aufgerufen. Ein neuer Ausführungskontext wird erstellt. Da es in Funktion a lexikalisch sitzt, ist seine äußere Umgebung a. Wenn also auf myVar verwiesen wird, da myVar nicht in der variablen Umgebung von Funktion b enthalten ist, wird es in der variablen Umgebung von Funktion a angezeigt. Es findet es dort und console.log druckt 2. Wenn sich die Variable jedoch nicht in der Variablenumgebung von Funktion a befand, wird die Bereichskette dort weiter suchen, da die äußere Umgebung von Funktion a der globale Ausführungskontext ist.
5) Nachdem die Ausführung von Funktion b und a abgeschlossen ist, werden sie aus dem Ausführungsstapel entfernt. Die Single-Threaded-JavaScript-Engine setzt die Ausführung im globalen Ausführungskontext fort. Es ruft die Funktion b auf. In der globalen Variablenumgebung gibt es jedoch keine b-Funktion und im globalen Ausführungskontext keine andere äußere Umgebung, nach der gesucht werden kann. Daher wird von der JavaScript Engine eine Ausnahme ausgelöst.
Das folgende Beispiel zeigt die Scope Chain in Aktion. In der Variablenumgebung des Ausführungskontexts der Funktion b gibt es kein myVar. Also durchsucht es seine äußere Umgebung, die die Funktion a ist. Die Funktion a hat myVar auch nicht in ihrer variablen Umgebung. Die Suchmaschinenfunktion funktioniert also mit der äußeren Umgebung von a, der äußeren Umgebung des globalen Ausführungskontexts, und myVar ist dort definiert. Daher gibt das console.log 1 aus.
In Bezug auf den Ausführungskontext und die damit verbundene lexikalische Umgebung, einschließlich der äußeren Umgebung und der Variablenumgebung, können Sie Variablen in JavaScript festlegen. Selbst wenn Sie dieselbe Funktion mehrmals aufrufen, wird für jeden Aufruf ein eigener Ausführungskontext erstellt. Jeder Ausführungskontext verfügt also über eine eigene Kopie der Variablen in seiner Variablenumgebung. Es gibt keine gemeinsame Nutzung von Variablen.
quelle
Dies geschieht, weil der Variablenname mit dem Funktionsnamen "a" identisch ist. Aufgrund des Hebens von Javascript wird versucht, den Namenskonflikt zu lösen, und es wird a = 1 zurückgegeben.
Ich war auch darüber verwirrt, bis ich diesen Beitrag auf "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html las
Ich hoffe es hilft.
quelle
Hier ist meine Zusammenfassung der Antwort mit mehr Anmerkungen und einer begleitenden Geige, mit der ich herumspielen kann.
https://jsfiddle.net/adjavaherian/fffpxjx7/
quelle
Scpope & Closure & Heben (Var / Funktion)
quelle
Heben In JavaScript werden Variablendeklarationen im gesamten Programm ausgeführt, bevor Code ausgeführt wird. Das Deklarieren einer Variablen an einer beliebigen Stelle im Code entspricht daher dem Deklarieren am Anfang.
quelle
Alles hängt vom Umfang der Variablen 'a' ab. Lassen Sie mich erklären, indem Sie Bereiche als Bilder erstellen.
Hier erstellt JavaScript 3 Bereiche.
i) Globaler Geltungsbereich. ii) Funktionsumfang b (). iii) Funktion a () Umfang.
Es ist klar, wenn Sie den Methodenbereich 'alert' aufrufen, der zu diesem Zeitpunkt zu Global gehört. Daher wird der Wert der Variablen 'a' nur aus dem globalen Bereich ausgewählt, der 1 ist.
quelle
Langer Beitrag!
Aber es wird die Luft reinigen!
Java Script funktioniert in zwei Schritten:
Kompilierung (sozusagen) - In diesem Schritt werden Variablen und Funktionsdeklarationen sowie deren jeweiliger Umfang registriert. Es geht nicht darum, den Funktionsausdruck
var a = function(){}
oder den Variablenausdruck zu bewerten (wie das Zuweisen3
zu,x
wennvar x =3;
dies nichts anderes ist als die Bewertung des RHS-Teils).Interpreter: Dies ist der Ausführungs- / Bewertungsteil.
Überprüfen Sie die Ausgabe des folgenden Codes, um ein Verständnis zu erhalten:
Lass es uns brechen:
In der Kompilierungsphase würde 'a' im globalen Bereich mit dem Wert '
undefined
' registriert . Gleiches gilt für 'c
', sein Wert wäre in diesem Moment 'undefined
' und nicht das 'function()
'. 'b
' würde als Funktion im globalen Bereich registriert. Innerhalbb
des Gültigkeitsbereichsf
würde ' ' als eine Variable registriert, die zu diesem Zeitpunkt undefiniert wäre, und die Funktion 'd
' würde registriert.Wenn der Interpreter ausgeführt wird, kann auf deklarierte Variablen und
function()
(und nicht auf Ausdrücke) zugegriffen werden, bevor der Interpreter die tatsächliche Ausdruckszeile erreicht. Variablen würden also 'undefined
' gedruckt und deklarierte anonyme Funktionen können früher aufgerufen werden. Der Versuch, vor der Initialisierung des Ausdrucks auf eine nicht deklarierte Variable zuzugreifen, führt jedoch zu einem Fehler wie:Was passiert nun, wenn Sie eine Variablen- und Funktionsdeklaration mit demselben Namen haben?
Die Antwort lautet : Funktionen werden immer vorher gehisst. Wenn dieselbe Namensvariable deklariert wird, wird sie als doppelt behandelt und ignoriert. Denken Sie daran, Reihenfolge spielt keine Rolle. Funktionen haben immer Vorrang. Während der Evaluierungsphase können Sie die Variablenreferenz jedoch auf alles ändern (sie speichert die letzte Zuordnung). Sehen Sie sich den folgenden Code an:
quelle
Heben ist ein Verhaltenskonzept von JavaScript. Heben (z. B. Bewegen) ist ein Konzept, das erklärt, wie und wo Variablen deklariert werden sollen.
In JavaScript kann eine Variable nach ihrer Verwendung deklariert werden, da Funktionsdeklarationen und Variablendeklarationen vom JavaScript-Interpreter immer unsichtbar an den Anfang ihres enthaltenen Bereichs verschoben ("gehisst") werden.
In den meisten Fällen gibt es zwei Arten des Hebens.
1.Variable Deklaration Heben
Lassen Sie uns dies unter diesem Code verstehen.
Hier wird die Deklaration der Variablen a vom Javascript-Interpreter zum Zeitpunkt der Kompilierung unsichtbar nach oben gehostet. So konnten wir Wert von a bekommen. Dieser Ansatz der Deklaration von Variablen wird jedoch nicht empfohlen, da wir Variablen bereits so nach oben deklarieren sollten.
Betrachten Sie ein anderes Beispiel.
wird tatsächlich so interpretiert:
In diesem Fall ist x undefiniert
Es spielt keine Rolle, ob der Code ausgeführt wurde, der die Deklaration der Variablen enthält. Betrachten Sie dieses Beispiel.
Diese Funktion stellt sich als solche heraus.
In der Variablendeklaration werden nur Hebezeuge mit variabler Definition verwendet, nicht die Zuordnung.
Im Gegensatz zum variablen Heben wird auch der Funktionskörper oder der zugewiesene Wert gehisst. Betrachten Sie diesen Code
Nachdem wir nun sowohl das Heben von Variablen als auch von Funktionen verstanden haben, wollen wir diesen Code jetzt verstehen.
Dieser Code wird sich als solcher herausstellen.
Die Funktion a () hat einen lokalen Gültigkeitsbereich innerhalb von b (). a () wird nach oben verschoben, während der Code mit seiner Definition interpretiert wird (nur im Fall von Funktionserhöhungen), sodass a jetzt einen lokalen Bereich hat und daher den globalen Bereich von a nicht beeinflusst, während es einen eigenen Bereich innerhalb der Funktion b () hat. .
quelle
Nach meinem Wissen geschieht das Heben mit der Variablendeklaration und der Funktionsdeklaration, zum Beispiel:
Was passiert in der JavaScript-Engine:
Oder:
Es wird werden:
Zuweisungen wie die Zuweisung von Variablen oder die Zuweisung von Funktionsausdrücken werden jedoch nicht gehisst: Zum Beispiel:
Es kann so werden:
quelle
Um das Hosting in Javascript in einem Satz zu beschreiben, werden Variablen und Funktionen an die Spitze des Bereichs angehoben, in dem sie deklariert sind.
Ich gehe davon aus, dass Sie ein Anfänger sind. Um das Heben zuerst richtig zu verstehen, haben wir den Unterschied zwischen undefiniert und ReferenceError verstanden
Was sehen wir jetzt im folgenden Code? Eine Variable und ein Funktionsausdruck werden deklariert.
aber das wirkliche Bild mit dem Beweis, dass sowohl die Variable als auch die Funktion oben in ihrem Bereich angehoben sind:
Die Ausgabe der ersten beiden Protokolle ist undefiniert und TypeError: getSum ist keine Funktion, da sowohl var totalAmo als auch getSum wie unten oben in ihrem Bereich angezeigt werden
Bei der Funktionsdeklaration werden jedoch ganze Funktionen über ihren Geltungsbereich angehoben.
Dieselbe Logik gilt nun für die Varibale, Funktionserfahrungen und Funktionsdeklarationen, die innerhalb des Funktionsumfangs deklariert wurden. Wichtigster Punkt: Sie werden nicht oben in die Datei gehievt .
Wenn Sie also das Schlüsselwort var verwenden , werden Variable und Funktion oben im Bereich des Bereichs (globaler Bereich und Funktionsbereich) angezeigt. Was ist mit let und const , const und let sind sich immer noch des globalen Bereichs und des Funktionsbereichs bewusst, genau wie var, aber const- und let-Variablen kennen auch einen anderen Bereich, der als blockierter Bereich bezeichnet wird. Ein Blockbereich ist immer dann vorhanden, wenn ein Codeblock vorhanden ist, z. B. for-Schleife, if else-Anweisung, while-Schleife usw.
Wenn wir const und let verwenden, um eine Variable in diesem Blockbereich zu deklarieren, wird die Variablendeklaration nur über dem Block angehoben, in dem sie sich befindet, und nicht über der übergeordneten Funktion oder über dem globaler Umfang, dass es gehisst wird.
Variablen im Abobe-Beispiel werden wie unten angehoben
quelle
ES5: Funktionsheben & variables Heben
das ist gleich
der Grund für das Heben
ES6
let
,const
kein Heben vorhandenrefs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
quelle