Der Lebenszyklus einer Funktion ist in Erstellungs- und Aktivierungsphasen (sofern aufgerufen) unterteilt. Lassen Sie uns ihn im Detail untersuchen.
Funktionserstellung
Wie wir alle wissen, werden Funktionsdeklarationen beim Eintritt in den Kontext in Variablen-/Aktivitätsobjekten (VO/AO) platziert. Schauen wir uns die Variablen- und Funktionsdeklarationen im globalen Kontext an (hier ist das Variablenobjekt das globale Objekt selbst, wir erinnern uns daran, oder?)
var x = 10; function foo() { var y = 20; alert(x + y); } foo(); // 30
Bei der Funktionsaktivierung erhalten wir das richtige (erwartete) Ergebnis - 30. Es gibt jedoch eine sehr wichtige Funktion.
Früher haben wir nur über variable Objekte gesprochen, die sich auf den aktuellen Kontext beziehen. Hier sehen wir, dass die Variable „y“ in der Funktion „foo“ definiert ist (was bedeutet, dass sie sich im AO des foo-Kontexts befindet), die Variable „x“ jedoch nicht im „foo“-Kontext definiert ist und dementsprechend es wird nicht zum AO von „foo“ hinzugefügt. Auf den ersten Blick existiert die Variable „x“ relativ zur Funktion „foo“ überhaupt nicht; aber wie wir unten sehen – und nur auf den „Blick“, stellen wir fest, dass das aktive Objekt des „foo“-Kontexts nur enthält ein Attribut – „y“.
fooContext.AO = { y: undefined // undefined – 进入上下文的时候是20 – at activation };
Wie greift die Funktion „foo“ auf die Variable „x“ zu? Theoretisch sollte die Funktion auf das Variablenobjekt eines übergeordneten Kontexts zugreifen können. Tatsächlich ist es genau so. Dieser Mechanismus wird über das Attribut [[scope]] innerhalb der Funktion implementiert.
[[scope]] ist eine hierarchische Kette aller übergeordneten Variablenobjekte, die über dem aktuellen Funktionskontext liegen und darin gespeichert werden, wenn die Funktion erstellt wird.
Beachten Sie diesen wichtigen Punkt – [[scope]] wird gespeichert, wenn die Funktion erstellt wird – statisch (unveränderlich), für immer und ewig, bis die Funktion zerstört wird. Das heißt: Die Funktion kann nie aufgerufen werden, aber das Attribut [[scope]] wurde geschrieben und im Funktionsobjekt gespeichert.
Eine weitere zu berücksichtigende Sache ist, dass [[scope]] im Gegensatz zur Bereichskette ein Attribut der Funktion und nicht des Kontexts ist. Betrachtet man das obige Beispiel, lautet der [[Bereich]] für die Funktion „foo“ wie folgt:
foo.[[Scope]] = [ globalContext.VO // === Global ];
Zum Beispiel verwenden wir die üblichen ECMAScript-Arrays, um Bereiche und [[Bereich]] darzustellen.
Weiterhin wissen wir, dass der Kontext eingegeben wird, wenn die Funktion aufgerufen wird. Zu diesem Zeitpunkt wird das aktive Objekt erstellt und dieses sowie der Bereich (Bereichskette) bestimmt. Betrachten wir diesen Moment im Detail.
Funktionsaktivierung
Wie in der Definition erwähnt, wird nach Eingabe des Kontexts zum Erstellen von AO/VO das Scope-Attribut des Kontexts (eine Bereichskette für die Variablensuche) wie folgt definiert:
Scope = AO|VO + [[Scope]]
Die Bedeutung des obigen Codes ist: Das aktive Objekt ist das erste Objekt des Bereichsarrays, das dem vorderen Ende des Bereichs hinzugefügt wird.
Scope = [AO].concat([[Scope]]);
Diese Funktion ist wichtig für die Verarbeitung des Identifier-Parsings. Bei der Bezeichnerauflösung wird ermittelt, zu welchem Variablenobjekt eine Variable (oder Funktionsdeklaration) gehört.
Im Rückgabewert dieses Algorithmus haben wir immer einen Referenztyp, seine Basiskomponente ist das entsprechende Variablenobjekt (oder null, wenn nicht gefunden) und die Attributnamenkomponente ist der Name des zu verwendenden Bezeichners schaute nach. Einzelheiten zu Referenztypen werden später besprochen.
Der Identifier-Auflösungsprozess besteht aus einer Suche nach den Attributen, die dem Variablennamen entsprechen, d. h. einer kontinuierlichen Suche nach den Variablenobjekten im Bereich, beginnend im tiefsten Kontext und unter Umgehung der Bereichskette nach oben .
Auf diese Weise haben bei der Aufwärtssuche lokale Variablen in einem Kontext eine höhere Priorität als Variablen im übergeordneten Bereich. Falls zwei Variablen denselben Namen haben, aber aus unterschiedlichen Bereichen stammen, befindet sich die erste gefundene Variable im tiefsten Bereich.
Wir verwenden ein etwas komplizierteres Beispiel, um zu beschreiben, was wir oben erwähnt haben.
var x = 10; function foo() { var y = 20; function bar() { var z = 30; alert(x + y + z); } bar(); } foo(); // 60
Dazu haben wir die folgenden Variablen/Aktivitäten, das [[scope]]-Attribut der Funktion und die Scope-Kette des Kontexts:
Das Variablenobjekt des Global Kontext ist:
globalContext.VO === Global = { x: 10 foo: <reference to function> };
Wenn „foo“ erstellt wird, ist das [[scope]]-Attribut von „foo“:
foo.[[Scope]] = [ globalContext.VO ];
Wenn „foo“ aktiviert ist (in den Kontext gelangt). ), „foo“ „Das aktive Objekt des Kontexts ist:
fooContext.AO = { y: 20, bar: <reference to function> };
Die Bereichskette des „foo“-Kontexts ist:
fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.: fooContext.Scope = [ fooContext.AO, globalContext.VO ];
Wenn die interne Funktion „bar“ erstellt wird, ist sein [[Bereich]]:
bar.[[Scope]] = [ fooContext.AO, globalContext.VO ];
Wenn „bar“ aktiviert ist, ist das aktive Objekt des „bar“-Kontexts:
barContext.AO = { z: 30 };
Die Bereichskette des „bar“-Kontexts ist:
barContext.Scope = barContext.AO + bar.[[Scope]] // i.e.: barContext.Scope = [ barContext.AO, fooContext.AO, globalContext.VO ];
Die Bezeichner von „x“, „y“ und „z“ werden wie folgt analysiert:
- "x" -- barContext.AO // not found -- fooContext.AO // not found -- globalContext.VO // found - 10 - "y" -- barContext.AO // not found -- fooContext.AO // found - 20 - "z" -- barContext.AO // found - 30
Das Obige ist das Zweiter Teil der JavaScript-Bereichskette: Der Inhalt des Lebenszyklus der Funktion, mehr verwandt. Bitte beachten Sie den Inhalt der chinesischen PHP-Website (m.sbmmt.com)!