Von der Definition bis zur Ausführung funktioniert die JS -Engine in der Implementierungsschicht viel Initialisierungsschicht. Vor dem Erlernen des Arbeitsmechanismus der JS -Engine müssen wir daher mehrere verwandte Konzepte einführen: Ausführungsumfeldstapel, globale Objekte, Ausführungsumgebung, variable Objekte, aktive Objekte, Umfangs- und Umfangsketten usw. Diese Konzepte sind die Kernkomponenten der Arbeit der JS -Engine. Der Zweck dieses Artikels ist nicht, Ihnen jedes Konzept isoliert zu erklären, sondern durch eine einfache Demo zu analysieren, die Details der JS -Engine von der Definition bis zur Ausführung zu erklären, und die Rolle, die diese Konzepte darin spielen.
var x = 1; // Definieren Sie eine globale Variable xfunktion a (y) {var x = 2; // eine lokale Variable x Funktion b (z) {// eine interne Funktion b console.log (x+y+z) definieren; } return b; // eine Referenz auf Funktion B} var c = a (1) zurückgeben; // a, return bc (1); // Funktion ausführen bDiese Demo ist eine Schließung, und das Ausführungsergebnis ist 4. Im Folgenden werden wir den Arbeitsmechanismus der JS -Engine in drei Stufen analysieren: Globale Initialisierung, Ausführungsfunktion A und Ausführungsfunktion B :
1. Globale Initialisierung
Wenn die JS -Engine in einen ausführbaren Code eingeht, muss die folgenden drei Initialisierungsaufgaben ausgeführt werden:
Erstellen Sie zunächst ein globales Objekt (globales Objekt). Es gibt nur eine globale Kopie dieses Objekts, auf seine Eigenschaften können überall zugegriffen werden, und seine Existenz wird den gesamten Lebenszyklus der Anwendung begleiten. Beim Erstellen eines globalen Objekts, häufig verwendete JS -Objekte wie Mathematik, Zeichenfolge, Datum, Dokument werden als Eigenschaften verwendet. Da dieses globale Objekt nicht direkt mit Namen zugegriffen werden kann, gibt es ein anderes Eigenschaftsfenster und zeigt das Fenster auf sich selbst, damit das globale Objekt über das Fenster zugegriffen werden kann. Die allgemeine Struktur der Verwendung von Pseudo-Code zur Simulation globaler Objekte lautet wie folgt:
// Erstellen Sie ein globales Objekt var GlobalObject = {Math: {}, String: {}, Datum: {}, Dokument: {}, // DOM -Operation ... Fenster: Dies // das Fensterattribut auf sich selbst zeigen}Anschließend muss die JS -Engine einen Ausführungskontextstapel erstellen. Gleichzeitig muss es auch einen globalen Ausführungskontext EC erstellen und diese globale Ausführungsumgebung EC in den Ausführungsumfeldstapel bringen. Die Funktion des Ausführungsumgebungsstacks besteht darin, sicherzustellen, dass das Programm in der richtigen Reihenfolge ausgeführt werden kann. In JavaScript hat jede Funktion eine eigene Ausführungsumgebung. Bei der Ausführung einer Funktion wird die Ausführungsumgebung der Funktion an die Spitze des Ausführungsumgebungsstapels gedrängt und die Ausführungsrechte erhalten. Wenn diese Funktion ausgeführt wird, wird die Ausführungsumgebung von der Spitze des Stapels gelöscht und das Ausführungsrecht in die vorherige Ausführungsumgebung zurückgegeben. Wir verwenden Pseudocode, um die Beziehung zwischen dem Ausführungsumgebungsstack und der EC zu simulieren:
var ecstack = []; // einen Ausführungsumgebungsstapel definieren, ähnlich wie Array var ec = {}; // Erstellen eines Ausführungsraums, // ECMA-262-Spezifikation definiert die Datenstruktur der EG nicht klar, Sie können sie als ein in Speicher ecstack.push (EC) zugewiesener Raum verstehen. // Geben Sie die Funktion ein und drücken Sie die Ausführungsumgebung ecstack.pop (EC); // Löschen Sie nach Rückgabe der Funktion die AusführungsumgebungSchließlich erstellt die JS -Engine auch ein globales variables Objekt (Varibale -Objekt) VO, das mit EC und Punkten VO zum globalen Objekt zugeordnet ist. VO enthält nicht nur die ursprünglichen Eigenschaften des globalen Objekts, sondern auch die Variable x und die Funktion a global definiert. Gleichzeitig wird bei der Definition von Funktion A ein internes Attributumfang auch zu A und Punktzahlen zu VO hinzugefügt. Wenn jede Funktion definiert ist, wird ein damit verbundenes Bereichsattribut erstellt, und der Umfang zeigt immer auf die Umgebung, in der die Funktion definiert ist. Die Ecstack -Struktur zu diesem Zeitpunkt lautet wie folgt:
Ecstack = [// Ausführungsumgebung Stack EC (g) = {// Globale Ausführungsumgebung Vo (g): {// Global Variable -Objekt definieren ... // Enthält die ursprünglichen Attribute des globalen Objekts x = 1; // Variable x a = function () {...} definieren; // Funktion aa [[Scope]] = this; // Umfang von A definieren und Vo selbst einen Wert zuweisen}}];2. FUNKTION A FORMUTE A.
Wenn die Ausführung in eine (1) eintritt, muss die JS -Engine Folgendes ausführen:
Zuerst erstellt die JS -Engine die Ausführungsumgebung EC von Funktion A, und dann schiebt die EG sie an die Spitze des Ausführungsumfeldstapels und erhält die Ausführungsrechte. Zu diesem Zeitpunkt gibt es zwei Ausführungsumgebungen im Ausführungsumfeldstapel, nämlich die globale Ausführungsumgebung und die Funktion einer Ausführungsumgebung. Die Ausführungsumgebung von A steht ganz oben auf dem Stapel, und die globale Ausführungsumgebung befindet sich am Ende des Stapels. Erstellen Sie dann die Funktionskette von A. In JavaScript haben jede Ausführungsumgebung eine eigene Bereichskette für die Auflösung von Identifikatoren. Wenn die Ausführungsumgebung erstellt wird, wird seine Bereichskette initialisiert, wie das Objekt im Bereich der derzeit laufenden Funktion enthalten ist.
Als nächstes erstellt die JS -Engine ein aktives Objekt (Aktivierungsobjekt) AO der aktuellen Funktion. Das aktive Objekt hier spielt die Rolle eines variablen Objekts, wird jedoch in der Funktion unterschiedlich bezeichnet (Sie können glauben, dass ein variables Objekt ein allgemeines Konzept ist und das aktive Objekt ein Zweig davon ist). AO enthält die formalen Parameter der Funktion, das Argumentenobjekt, dieses Objekt sowie die Definitionen lokaler Variablen und interner Funktionen, und dann wird AO an die Spitze der Bereichskette gedrückt. Es ist zu beachten, dass die JS -Engine bei der Definition von Funktion B auch ein Bereichsattribut zu B und Punktumfang zu der Umgebung hinzufügt, in der die Funktion B definiert ist. Die Umgebung, in der die Funktion B definiert ist, ist das aktive Objekt AO von A, und AO befindet sich am vorderen Ende der verknüpften Liste. Da die verknüpfte Liste die Eigenschaften der Endverbindung aufweist, zeigt wir den Funktionsumfang B auf die gesamte Geltungsbereich von A. Schauen wir uns die Ecstack -Struktur zu diesem Zeitpunkt an:
Ecstack = [// Ausführungsumgebung Stack EC (a) = {// As Ausführungsumgebung [Scope]: Vo (g), // vo ist das globale Variable -Objekt ao (a): {// Erstellen Sie das aktive Objekt y: 1, x: 2, // Definieren Sie die lokale Variable x b: function () {...}, // die Funktion bb [scope] this; // Dies bezieht sich auf AO selbst, und AO steht ganz oben auf dem Scopechain, also zeigt B [[Scope]] auf die gesamten Argumente der Kettenkette: [], // Die Argumente, auf die wir in der Funktion zugreifen, sind Argumente in AO. Dann wird AO an die Oberseite der Bereichskette hinzugefügt. Zu diesem Zeitpunkt die Bereichs Kette von A: ao (a)-> vo (g)}, ec (g) = {// Globale Ausführungsumgebung vo (g): {// Global Variable-Objekt erstellen ... // Enthält die ursprünglichen Attribute des globalen Objekts x = 1; // Definieren Sie die Variable x a = function () {...}; // Definieren Sie die Funktion aa [[Scope]] = this; // Definieren Sie den Umfang a, a [[Scope]] == vo (g)}}];3. Ausführen von Funktion B ausführen
Nach der Ausführung von Funktion A wird der Verweis auf B zurückgegeben und der Variablen C C (1) zugeordnet. Die Ausführung von B (1) entspricht. Der JS -Motor muss die folgenden Aufgaben erledigen:
Erstellen Sie zuerst, wie oben, die Ausführungsumgebung EC von Funktion B und dann die EG an die Spitze des Ausführungsumfeldstapels und erhalten Sie die Ausführungsrechte. Zu diesem Zeitpunkt gibt es zwei Ausführungsumgebungen im Ausführungsumfeldstapel, nämlich die globale Ausführungsumgebung und die Ausführungsumgebung der Funktion B. Die Ausführungsumgebung von B steht ganz oben auf dem Stapel, und die globale Ausführungsumgebung befindet sich am Ende des Stapels. (Note: When function A returns, A's execution environment will be deleted from the stack, leaving only the global execution environment) Then, create the scope chain of function B and initialize it into the object contained in the scope of function B, that is, the scope chain of A. Finally, create the active object AO of function B, and use the parameters z, arguments object and this object of B as properties of AO. Zu diesem Zeitpunkt wird Ecstack wie folgt:
Ecstack = [// Ausführungsumgebung Stack EC (b) = {// bs Ausführungsumgebung erstellen und oben in der SCOPE-Kette [Scope]: ao (a), // auf die SCOPE-Kette der Funktion A, ao (a)-> vo (g) var ao (b) = {// Das aktive Objekt von Funktion B Z: 1,: [Argumente: [Argumente: [],: Scopechain: <AO (B), B [[Scope]]> // Die verknüpfte Liste wird in B [[Scope]] initialisiert und dann wird AO (B) zum Header der verknüpften Liste hinzugefügt. Zu diesem Zeitpunkt wurde Bs Scope-Kette: ao (b)-> ao (a) -vo (g)}, ec (a), // As Ausführungsumgebung von der Spitze des Stacks gelöscht, EC (g) = {// globale Ausführungsumgebung vo: {// Global Variable Object ... // enthalten die ursprünglichen Attribute des globalen Objekts des globalen Objekts. // Variable x a = function () {...} definieren; // Funktion aa [[Scope]] = this; // Umfang von a, a [[scope]] == vo (g)}}];Wenn die Funktion B "x+y+z" ausführt, müssen die drei Bezeichnungen x, y und z einzeln analysiert werden. Der Analyseprozess hält die variablen Suchregeln an: Finden Sie zunächst, ob das Attribut in Ihrem aktiven Objekt vorhanden ist. Wenn es existiert, hören Sie auf zu suchen und kehren Sie zurück. Wenn es nicht existiert, suchen Sie weiter von oben entlang seiner Bereichskette, bis es gefunden wird. Wenn die Variable nicht in der gesamten Bereichskette gefunden wird, kehren Sie "undefiniert" zurück. Aus der obigen Analyse können wir feststellen, dass die Funktionsumfangskette B wie folgt lautet:
Ao (b)-> ao (a)-> vo (g)
Daher wird die Variable X in AO (a) gefunden und sucht nicht nach X in VO (g), die Variable y wird in AO (a) und die Variable Z in seiner eigenen AO (B) gefunden. Das Ausführungsergebnis: 2+1+1 = 4.
Einfache Zusammenfassung
Nachdem wir den Arbeitsmechanismus der JS -Engine verstanden haben, können wir nicht einfach auf dem Niveau des Konzepts bleiben, sondern als grundlegendes Werkzeug zur Optimierung und Verbesserung unseres Code in der tatsächlichen Arbeit, die Ausführungseffizienz und die Erzeugung des tatsächlichen Werts. Nehmen Sie den variablen Suchmechanismus als Beispiel. Wenn Ihr Code tief verschachtelt ist und Sie jedes Mal, wenn Sie sich auf eine globale Variable beziehen, sucht die JS -Engine nach der gesamten Bereichskette. Beispielsweise gibt es dieses Problem mit Fenster- und Dokumentobjekten am unteren Rand der Bereichskette. Daher können wir eine Menge Leistungsoptimierung in diesem Problem durchführen, und natürlich gibt es andere Aspekte von Optimierungen. Ich werde hier nicht auf Details eingehen. Dieser Artikel wird nur als Tipps angesehen!
von @一竞 2015
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.