Beispielerklärung für Ausführungskontext und Ausführungsstapel in JavaScript

Beispielerklärung für Ausführungskontext und Ausführungsstapel in JavaScript

JavaScript - Prinzipienreihe

Wenn wir in der täglichen Entwicklung ein bestehendes Projekt übernehmen, schauen wir uns immer gerne zuerst den Code an, der von anderen geschrieben wurde. Wenn wir jemanden coolen Code schreiben sehen, seufzen wir immer! Wie haben Sie das Talent entwickelt, solch schönen und prägnanten Code zu schreiben?

Wie kann ich das gleiche Niveau wie die Großen erreichen? Okay, kommen wir ohne weitere Umschweife zum heutigen Thema.

1. Ausführungskontext

Kurz gesagt ist [Ausführungskontext] ein abstraktes Konzept der Umgebung, in der JavaScript-Code analysiert und ausgeführt wird. Jeder in JavaScript ausgeführte Code wird in seinem Ausführungskontext ausgeführt.

Wenn Sie beim Ausführen von JavaScript-Code Code ausführen müssen, gelangt dieser zuerst in eine Umgebung (Browser, Node-Client). Anschließend wird ein Ausführungskontext für die Umgebung erstellt, der vor der Ausführung des Codes einige Vorbereitungen trifft, z. B. das Bestimmen des Umfangs, das Erstellen globaler und lokaler Variablenobjekte usw.

Klassifizierung von Ausführungskontexten

  • Globaler Ausführungskontext:

Dies ist der standardmäßige und grundlegendste Ausführungskontext. Code, der sich in keiner Funktion befindet, befindet sich im globalen Ausführungskontext.

Es bewirkt zwei Dinge:

  • Erstellen Sie ein globales Objekt. Im Browser ist dieses globale Objekt das Fensterobjekt.

Legen Sie this Zeiger so fest, dass er auf das globale Objekt zeigt. In einem Programm kann es nur einen globalen Ausführungskontext geben.

  • Kontext der Funktionsausführung:

Bei jedem Aufruf einer Funktion wird ein neuer Ausführungskontext für diese Funktion erstellt. Jede Funktion verfügt über einen eigenen Ausführungskontext, der jedoch erst beim Aufruf der Funktion erstellt wird. In einem Programm kann es eine beliebige Anzahl von Funktionsausführungskontexten geben. Immer wenn ein neuer Ausführungskontext erstellt wird, führt er eine Reihe von Schritten in einer bestimmten Reihenfolge aus, die später in diesem Artikel erläutert werden.

  • Ausführungskontext der Eval-Funktion:

Der in der eval Funktion ausgeführte Code erhält auch seinen eigenen Ausführungskontext. Da JavaScript-Entwickler die eval-Funktion jedoch nicht oft verwenden, wird sie hier nicht erläutert.

Begrenzung der Anzahl von Ausführungskontexten (Stapelüberlauf)

Es kann mehrere Ausführungskontexte geben. Obwohl es keine klare Begrenzung für die Anzahl gibt, kommt es zu einem Stapelüberlauf, wenn der vom Stapel zugewiesene Speicherplatz überschritten wird. Dies kommt häufig bei rekursiven Aufrufen vor, bei denen es keine Abbruchbedingung gibt, was zu einer Endlosschleife führt.

Hier ist der Beispielcode:

// Ruft sich selbst rekursiv auf function foo() {
  foo();
}
foo();
// Fehler: Nicht erfasster RangeError: Maximale Aufrufstapelgröße überschritten

Tipps:

JS ist „single-threaded“ und führt immer nur einen Codeabschnitt auf einmal aus.

2. Ausführungsstapel

Der Ausführungsstapel in JS, in anderen Programmiersprachen auch als „Aufrufstapel“ bekannt, ist ein Stapel mit einer LIFO-Datenstruktur (Last In, First Out), der zum Speichern aller Ausführungskontexte verwendet wird, die beim Ausführen des Codes erstellt werden.

Wenn die JavaScript-Engine zum ersten Mal auf Ihr Skript stößt, erstellt sie einen globalen Ausführungskontext und schiebt ihn in den aktuellen Ausführungsstapel. Immer wenn die Engine auf einen Funktionsaufruf stößt, erstellt sie einen neuen Ausführungskontext für diese Funktion und schiebt ihn ganz oben auf den Stapel.

Die Engine führt die Funktion aus, deren Ausführungskontext sich oben auf dem Stapel befindet. Wenn die Ausführung der Funktion abgeschlossen ist, wird der Ausführungskontext aus dem Stapel entfernt und der Kontrollfluss erreicht den nächsten Kontext im aktuellen Stapel.

Stapeldatenstruktur

Lassen Sie uns nun einen Codeabschnitt verwenden, um den Ausführungsstapel zu verstehen

let a = 'Hallo Welt!';

Funktion zuerst() {
 console.log('Innerhalb der ersten Funktion');
 zweite();
 console.log('Wieder innerhalb der ersten Funktion');
}

Funktion Sekunde() {
 console.log('Innerhalb der zweiten Funktion');
}

Erste();
console.log('Im globalen Ausführungskontext');

Die folgende Abbildung zeigt den Ausführungsstapel des obigen Codes

Wenn der obige Code im Browser geladen wird, erstellt die JavaScript-Engine des Browsers einen globalen Ausführungskontext und schiebt ihn in den aktuellen Ausführungsstapel. Wenn ein Funktionsaufruf erfolgt, erstellt die JavaScript-Engine einen neuen Ausführungskontext für die Funktion und schiebt ihn oben auf den aktuellen Ausführungsstapel.

Wenn die zweite first() second() -Funktion aufgerufen wird, erstellt die JavaScript-Engine einen neuen Ausführungskontext für second() -Funktion und schiebt sie oben auf den aktuellen Ausführungsstapel. Wenn second() abgeschlossen ist, wird ihr Ausführungskontext vom aktuellen Stapel entfernt und der Kontrollfluss erreicht den nächsten Ausführungskontext, der der Ausführungskontext der Funktion first() ist.

Wenn die Ausführung first() abgeschlossen ist, wird sein Ausführungskontext vom Stapel entfernt und die Steuerung wechselt zum globalen Ausführungskontext. Sobald der gesamte Code ausgeführt ist, entfernt die JavaScript-Engine den globalen Ausführungskontext aus dem aktuellen Stapel.

Die Erstellungsphase

Bevor JavaScript-Code ausgeführt wird, durchläuft der Ausführungskontext eine Erstellungsphase. Während der Erstellungsphase passieren drei Dinge:

  1. Die Bestimmung dieses Wertes wird als This-Bindung bezeichnet.
  2. Erstellt eine LexicalEnvironment-Komponente.
  3. Erstellen Sie eine variable Umgebungskomponente.

Der Ausführungskontext wird konzeptionell wie folgt dargestellt:

Ausführungskontext = {
 ThisBinding = <dieser Wert>,
 Lexikalische Umgebung = { ... },
 Variablenumgebung = { ... },
}

Diese Bindung:

Im globalen Ausführungskontext bezieht sich der Wert this auf das globale Objekt. (In einem Browser bezieht sich this auf das Fensterobjekt).

Im Kontext einer Funktionsausführung hängt der Wert this ab, wie die Funktion aufgerufen wird. Wenn es mit einem Referenzobjekt aufgerufen wird, wird this auf dieses Objekt gesetzt, andernfalls wird der this auf das globale Objekt gesetzt oder (im strikten Modus) undefined . Zum Beispiel:

lass foo = {
 baz: Funktion() {
 konsole.log(dies);
 }
}
foo.baz(); // „this“ bezieht sich auf „foo“, weil „baz“ // für das Objekt „foo“ aufgerufen wird let bar = foo.baz;
bar(); // 'this' bezieht sich auf das globale Fensterobjekt, da // kein Referenzobjekt angegeben ist

Lexikalische Umgebung

Die offizielle ES6-Dokumentation definiert eine lexikalische Umgebung als

Eine lexikalische Umgebung ist ein Spezifikationstyp, der die Zuordnung von Bezeichnern zu bestimmten Variablen und Funktionen basierend auf der lexikalischen Verschachtelungsstruktur von ECMAScript-Code definiert. Eine lexikalische Umgebung besteht aus einem Umgebungsrekorder und einem möglicherweise leeren Wert, der auf eine äußere lexikalische Umgebung verweist.


Einfach ausgedrückt ist eine lexikalische Umgebung eine Struktur, die Bezeichner-Variablen-Zuordnungen enthält. (Hier bezieht sich der Bezeichner auf den Namen der Variable/Funktion, während die Variable ein Verweis auf das eigentliche Objekt [einschließlich Objekte des Funktionstyps] oder primitive Daten ist).

Nun gibt es innerhalb eines LexicalEnvironment zwei Komponenten: (1) einen EnvironmentRecordant und (2) eine Referenz auf das outerEnvironment.

  1. Der Umgebungsrekorder ist der eigentliche Ort, an dem Variablen- und Funktionsdeklarationen gespeichert werden.
  2. Ein Verweis auf die äußere Umgebung bedeutet, dass er Zugriff auf die übergeordnete lexikalische Umgebung (Bereich) hat.

Es gibt zwei Arten von lexikalischen Umgebungen:

  • Die globale Umgebung (im globalen Ausführungskontext) ist eine lexikalische Umgebung, auf die keine äußeren Umgebungen verwiesen werden. Die äußere Umgebungsreferenz der globalen Umgebung ist null. Es verfügt über integrierte Objekte/Arrays/usw., Prototypfunktionen im Umgebungsrekorder (die mit dem globalen Objekt verknüpft sind, z. B. dem Fensterobjekt) und alle benutzerdefinierten globalen Variablen, und der Wert this bezieht sich auf das globale Objekt.
  • In einer Funktionsumgebung werden benutzerdefinierte Variablen innerhalb einer Funktion im Umgebungsrekorder gespeichert. Bei der genannten äußeren Umgebung kann es sich um die globale Umgebung oder um eine beliebige äußere Funktion handeln, die diese innere Funktion enthält.

Es gibt auch zwei Arten von Umgebungsloggern (wie oben!):

  1. Deklarative Umgebungsrekorder speichern Variablen, Funktionen und Parameter.
  2. Mit dem Objektumgebungsrekorder werden die Beziehungen zwischen Variablen und Funktionen definiert, die im globalen Kontext auftreten.

Zusamenfassend

  • In der globalen Umgebung ist der Umgebungslogger der Objektumgebungslogger.
  • In einer Funktionsumgebung ist der Umgebungsprotokollierer ein deklarativer Umgebungsprotokollierer.

Beachten

Bei Funktionsumgebungen enthält der deklarative Umgebungsrekorder auch ein an die Funktion übergebenes arguments (dieses Objekt speichert eine Zuordnung von Indizes und Parametern) und die Länge der an die Funktion übergebenen Argumente.

Abstrakt sieht eine lexikalische Umgebung in Pseudocode folgendermaßen aus:

GlobalExecutionContext = {
 Lexikalische Umgebung:
  Umgebungsdatensatz: {
   Typ: "Objekt",
   // Bind-ID hier }
  außen: <null>
 }
}

Funktionsausführungskontext = {
 Lexikalische Umgebung:
  Umgebungsdatensatz: {
   Typ: "Deklarativ",
   // Bind-ID hier }
  outer: <Globale oder äußere Funktionsumgebungsreferenz>
 }
}

Variable Umgebung:

Es handelt sich außerdem um eine lexikalische Umgebung, deren Umgebungsrekorder die durch Variablendeklarationsanweisungen im Ausführungskontext erstellten Bindungen enthält.

Wie oben erwähnt, ist eine variable Umgebung auch eine lexikalische Umgebung und verfügt daher über alle oben definierten Eigenschaften einer lexikalischen Umgebung.

In ES6 besteht ein Unterschied zwischen der Komponente „LexicalEnvironment“ und der Komponente „VariableEnvironment“ darin, dass erstere zum Speichern von Funktionsdeklarationen und Variablenbindungen ( let und const ) verwendet wird, während letztere nur zum Speichern var Variablenbindungen verwendet wird.

Schauen wir uns einige Beispielcodes an, um die oben genannten Konzepte zu verstehen:

sei a = 20;const b = 30;var c;
Funktion multiplizieren(e, f) { var g = 20; return e * f * g;}
c = Multiplikation(20, 30);

Der Ausführungskontext sieht folgendermaßen aus:

GlobalExecutionContext = {

 ThisBinding: <Globales Objekt>,

 Lexikalische Umgebung:
  Umgebungsdatensatz: {
   Typ: "Objekt",
   //Bind-ID a hier: <uninitialized>,
   b: <nicht initialisiert>,
   multiplizieren: <func>
  }
  außen: <null>
 },

 Variablenumgebung: {
  Umgebungsdatensatz: {
   Typ: "Objekt",
   //Bind-Bezeichner c hier: undefiniert,
  }
  außen: <null>
 }
}

Funktionsausführungskontext = {
 ThisBinding: <Globales Objekt>,

 Lexikalische Umgebung:
  Umgebungsdatensatz: {
   Typ: "Deklarativ",
   // Bezeichner hier binden Argumente: {0: 20, 1: 30, Länge: 2},
  },
  außen: <GlobalLexicalEnvironment>
 },

Variablenumgebung: {
  Umgebungsdatensatz: {
   Typ: "Deklarativ",
   //Bind-ID g hier: undefiniert
  },
  außen: <GlobalLexicalEnvironment>
 }
}

Beachten

Der Funktionsausführungskontext wird nur erstellt, wenn die Funktion multiply aufgerufen wird.

Möglicherweise ist Ihnen aufgefallen, dass mit let und const definierten Variablen keine Werte zugeordnet sind, mit var definierten Variablen jedoch auf undefined gesetzt sind.

Dies liegt daran, dass die Engine während der Erstellungsphase den Code nach Variablen- und Funktionsdeklarationen durchsucht. Während Funktionsdeklarationen vollständig in der Umgebung gespeichert sind, werden Variablen zunächst auf undefined “ (im Fall von var ) bzw. „nicht initialisiert“ (im Fall von let und const “) gesetzt.

Aus diesem Grund können Sie auf eine Variable zugreifen, die vor der Deklaration mit var definiert wurde (obwohl sie undefined ist), Sie erhalten jedoch einen Referenzfehler, wenn Sie auf eine Variable zugreifen, die vor der Deklaration mit let " oder " const definiert wurde.

Dies ist das, was wir als Heben der Variablendeklaration bezeichnen.

Ausführungsphase

​Dies ist der einfachste Teil des gesamten Artikels. In dieser Phase werden die Zuweisungen zu allen diesen Variablen vorgenommen und schließlich der Code ausgeführt.

Beachten

Wenn die JavaScript-Engine während der Ausführungsphase den Wert der Variable let nicht an der tatsächlichen Stelle finden kann, an der sie im Quellcode deklariert ist, wird ihr der Wert undefined zugewiesen.

abschließend

Wir haben bereits besprochen, wie JavaScript-Programme intern ausgeführt werden. Obwohl Sie nicht alle diese Konzepte erlernen müssen, um ein hervorragender JavaScript-Entwickler zu werden, hilft Ihnen ein gutes Verständnis der oben genannten Konzepte dabei, andere Konzepte wie das Heben von Variablendeklarationen, den Gültigkeitsbereich und Abschlüsse einfacher und gründlicher zu verstehen.

Referenzartikel:

https://juejin.cn/post/6844903682283143181

https://www.jianshu.com/p/6f8556b10379

https://juejin.cn/post/6844903704466833421

Dies ist das Ende dieses Artikels über Beispiele für Ausführungskontext und Ausführungsstapel in JavaScript. Weitere Informationen zum Ausführungskontext und Ausführungsstapel in JavaScript finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung des JavaScript-Ausführungsmechanismus
  • Den Ausführungsmechanismus von JavaScript genau verstehen
  • Detaillierte Erklärung des Ausführungskontexts und des Aufrufstapels in JavaScript
  • JS-Prinzip der asynchronen Ausführung und Rückrufdetails
  • Detaillierte Erläuterung des JavaScript-Ausführungsmodells
  • Ausführliche Erläuterung der Kontextreihenfolge der Javascript-Ausführung
  • So implementieren Sie manuell einen JavaScript-Modul-Executor
  • Detaillierte Erläuterung der seriellen Ausführung asynchroner Prozesse in Javascript
  • Verwenden Sie einige Interviewfragen, um den Ausführungsmechanismus von JavaScript zu untersuchen

<<:  Einführung in Docker-Container

>>:  MySQL 5.7.17 neuestes Installationstutorial mit Bildern und Text

Artikel empfehlen

MySql 8.0.11 Installations- und Konfigurationstutorial

Offizielle Website-Adresse: https://dev.mysql.com...

Probleme und Lösungen für MYSQL5.7.17-Verbindungsfehler unter MAC

Das Problem, dass MYSQL5.7.17 unter MAC keine Ver...

Django2.* + Mysql5.7-Entwicklungsumgebung Integrations-Tutorial-Diagramm

Umfeld: MAC_OS 10.12 Python 3.6 MySQL 5.7.25 Djan...

Lösung für „Ubuntu kann keine Verbindung zum Netzwerk herstellen“

Effektive Lösung für Ubuntu, wenn in einer virtue...

Zusammenfassung der grundlegenden Operationen für MySQL-Anfänger

Bibliotheksbetrieb Abfrage 1.SHOW DATABASE; ----A...

UTF-8- und GB2312-Webkodierung

In letzter Zeit haben mich viele Studenten zur Ko...

Erläuterung des Arbeitsmechanismus von Namenode und SecondaryNameNode in Hadoop

1) Prozess 2) FSImage und Bearbeitungen Nodenode ...

JavaScript zum Erzielen eines einfachen Drag-Effekts

In diesem Artikel wird der spezifische JavaScript...

Grundlegendes Tutorial zur Steuerung des mobilen Roboters Turtlebot3 mit ROS

Chinesisch-Tutorial https://www.ncnynl.com/catego...

JavaScript implementiert Konstellationsabfragefunktion mit detailliertem Code

Inhaltsverzeichnis 1. Titel 2. Code 3. Ergebnisse...

Detaillierte Erläuterung der primitiven Werte und Referenzwerte in ECMAScript

Inhaltsverzeichnis Vorwort Was sind dynamische Ei...

Informationen zu UDP in Linux

Inhaltsverzeichnis 1. Einführung in UDP und Linux...

HTML/CSS (der erste Leitfaden, den Anfänger unbedingt lesen sollten)

1. Die Bedeutung von Webstandards verstehen - War...