103 Stimmen

Javascript-Funktion scoping und hoisting

Ich habe gerade einen tollen Artikel gelesen über JavaScript-Scoping und Heben von Ben Cherry in dem er das folgende Beispiel anführt:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

Bei Verwendung des obigen Codes meldet der Browser "1".

Ich bin mir immer noch nicht sicher, warum er eine "1" zurückgibt. Einige der Dinge, die er sagt, kommen mir in den Sinn wie: Alle Funktionsdeklarationen werden nach oben gehievt. Man kann eine Variable mit einer Funktion in den Gültigkeitsbereich bringen. Trotzdem verstehe ich es nicht.

134voto

Peter Olson Punkte 130102

Das Hochziehen von Funktionen bedeutet, dass Funktionen an den Anfang ihres Bereichs verschoben werden. Das heißt,

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

wird vom Interpreter in diesen Text umgeschrieben

function b() {
  function a() {}
  a = 10;
  return;
}

Seltsam, nicht wahr?

Auch in diesem Fall,

function a() {}

verhielt sich genauso wie

var a = function () {};

Das ist es also, was der Code im Wesentlichen tut:

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"

6voto

kemiller2002 Punkte 110605

Dabei ist zu beachten, dass die gesamte Funktion geparst und alle Variablendeklarationen aufgelöst werden, bevor sie ausgeführt wird. So....

function a() {} 

wird wirklich

var a = function () {}

var a zwingt sie in einen lokalen Bereich, und der Variablenbereich erstreckt sich über die gesamte Funktion, so dass die globale Variable a immer noch 1 ist, weil Sie a in einem lokalen Bereich deklariert haben, indem Sie es zu einer Funktion gemacht haben.

5voto

Digital Plane Punkte 36384

Die Funktion a wird innerhalb der Funktion gehievt b :

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

was fast so ist wie die Verwendung von var :

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

Die Funktion wird lokal deklariert, und die Einstellung a geschieht nur im lokalen Bereich, nicht in der globalen Var.

3voto

Jhankar Mahbub Punkte 9404
  1. Funktionsdeklaration function a(){} wird zuerst hochgezogen und verhält sich wie var a = function () {}; daher im lokalen Geltungsbereich a erstellt wird.
  2. Wenn Sie zwei Variablen mit demselben Namen haben (eine in global eine andere in lokal), haben lokale Variablen immer Vorrang vor globalen Variablen.
  3. Wenn Sie die a=10 setzen Sie die lokale Variable a und nicht die globale.

Daher bleibt der Wert der globalen Variablen gleich und Sie erhalten die Meldung 1

2voto

Daniel Viglione Punkte 6606

Erstaunlicherweise wird in keiner der Antworten die Relevanz des Ausführungskontextes in der Scope Chain erwähnt.

Die JavaScript-Engine verpackt den aktuell ausgeführten Code in einen Ausführungskontext. Der Basis-Ausführungskontext ist der globale Ausführungskontext. Jedes Mal, wenn eine neue Funktion aufgerufen wird, wird ein neuer Ausführungskontext erstellt und auf dem Ausführungsstapel abgelegt. Stellen Sie sich einen Stack Frame vor, der in anderen Programmiersprachen auf einem Invocation Stack sitzt. Wer zuletzt kommt, mahlt zuerst. Nun hat jeder Ausführungskontext seine eigene variable Umgebung und äußere Umgebung in JavaScript.

Zur Veranschaulichung möchte ich das folgende Beispiel verwenden.

1) Zunächst wird die Erstellungsphase des globalen Ausführungskontexts eingeleitet. Sowohl die äußere Umgebung als auch die variable Umgebung der lexikalischen Umgebung werden erstellt. Das globale Objekt wird eingerichtet und im Speicher abgelegt, wobei die spezielle Variable "this" auf es verweist. Die Funktion a und ihr Code sowie die Variable myVar mit einem undefinierten Wert werden im Speicher der globalen variablen Umgebung abgelegt. Er wird lediglich mit der Funktion a im Speicher abgelegt.

2) Zweitens ist dies die Ausführungsphase des Ausführungskontexts. myVar ist nicht länger ein undefinierter Wert. Er wird mit dem Wert 1 initialisiert, der in der globalen Variable Environment gespeichert ist. Die Funktion a wird aufgerufen und ein neuer Ausführungskontext wird erstellt.

3) Im Ausführungskontext der Funktion a durchläuft sie die Erstellungs- und Ausführungsphase ihres eigenen Ausführungskontexts. Sie hat ihre eigene äußere Umgebung und ihre variable Umgebung, also ihre eigene lexikalische Umgebung. Die Funktion b und die Variable myVar werden in ihrer variablen Umgebung gespeichert. Diese variable Umgebung unterscheidet sich von der globalen variablen Umgebung. Da die Funktion a lexikalisch (physisch im Code) auf derselben Ebene wie der globale Ausführungskontext angesiedelt ist, ist ihre äußere Umgebung der globale Ausführungskontext. Wenn die Funktion a also auf eine Variable verweist, die sich nicht in ihrer Variablenumgebung befindet, durchsucht sie die Scope Chain und versucht, die Variable in der Variablenumgebung des globalen Ausführungskontexts zu finden.

4) Die Funktion b wird in der Funktion a aufgerufen. Es wird ein neuer Ausführungskontext erstellt. Da er sich lexikalisch in der Funktion a befindet, ist seine äußere Umgebung a. Wenn er also auf myVar verweist, wird er, da myVar nicht in der variablen Umgebung der Funktion b ist, in der variablen Umgebung der Funktion a suchen. Dort wird er gefunden und console.log gibt 2 aus. Befindet sich die Variable jedoch nicht in der Variablenumgebung von Funktion a, so sucht die Scope Chain dort weiter, da die äußere Umgebung von Funktion a der globale Ausführungskontext ist.

5) Nachdem die Funktionen b und a ausgeführt wurden, werden sie aus dem Ausführungsstapel entfernt. Die Single-Thread-JavaScript-Engine setzt die Ausführung im globalen Ausführungskontext fort. Sie ruft die Funktion b auf. Es gibt jedoch keine Funktion b in der globalen Variablenumgebung und es gibt keine andere äußere Umgebung, die im globalen Ausführungskontext zu suchen wäre. Daher wird von der JavaScript-Engine eine Ausnahme ausgelöst.

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

Das folgende Beispiel zeigt die Scope Chain in Aktion. In der Variablenumgebung des Ausführungskontexts der Funktion b gibt es keine myVar. Also wird die äußere Umgebung der Funktion a durchsucht. Die Funktion a hat myVar ebenfalls nicht in ihrer variablen Umgebung. Die Engine durchsucht also die äußere Umgebung der Funktion a, die die äußere Umgebung des globalen Ausführungskontexts ist, und myVar ist dort definiert. Daher wird in console.log die Zahl 1 ausgegeben.

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 1

Der Ausführungskontext und die damit verbundene lexikalische Umgebung, einschließlich äußerer Umgebung und variabler Umgebung, ermöglichen das Scoping von Variablen in JavaScript. Selbst wenn Sie dieselbe Funktion mehrmals aufrufen, wird für jeden Aufruf ein eigener Ausführungskontext erstellt. Jeder Ausführungskontext hat also seine eigene Kopie der Variablen in seiner Variablenumgebung. Es gibt keine gemeinsame Nutzung von Variablen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X