JavaScript 実行コンテキストとは何かを理解する前に、JavaScript コードをどのように、どの環境で実行できるかを知る必要があります。
まず、JavaScript は 2 つの環境で実行できます:
コンピューター上で JavaScript コードを作成して実行しようとすると、コードはまずブラウザーまたは Node.js に送られます。
ただし、私たちが作成した JavaScript コードは、ブラウザーや Node.js によって直接理解されるわけではありません。この時点で、どちらも組み込みの JavaScript エンジンにコードを送信します。エンジンにはさまざまな種類があります。例:
次に、JavaScript エンジンは JavaScript コードをマシンコードにコンパイルします。このマシン コードはコンピューターに送信され、コンピューターによって実行され、出力が表示されます。
プログラマーとして、この中間ステップ、つまり、JavaScript エンジンが JavaScript コードをマシンコードにコンパイルする方法をよく理解する必要があります。
それでは、JavaScript エンジンがどのように動作するかを理解する必要があります。 JavaScript エンジンは、コードをマシンコードに変換するために 2 つの方法で動作します。 1 つ目は解釈、2 つ目はコンパイルです。では、解釈と編集とは何ですか?
インタープリタは、高級言語で書かれたすべてのソースコードを 1 行ずつ読み取り、読み取った直後に各行をマシンコードに変換するプロセスです。コード行の読み取り中にエラーが発生した場合、プロセスはそこで停止するため、プログラマはエラーを特定しやすくなります。これにより、デバッグが簡単になります。ただし、このプロセスはコードを 1 行ずつ読み取るため、比較的遅くなります。
コンパイルは、高級言語で書かれたすべてのソース コードを一度にマシン コードに変換するプロセスです。この場合、コードにエラーがあってもコンパイルは行われ、実行時にのみエラーが表示されます。その結果、プログラマーがエラーを特定することが難しくなり、デバッグがより困難になります。ただし、ソース コード全体が一度に機械語コードに変換されるため、このプロセスは比較的高速です。そこで次の疑問が生じます: JavaScript はコンパイルされた言語ですか、それともインタプリタ言語ですか?
当初、JavaScript は主にインタープリタ型言語と考えられていました。ただし、このプロセスは非常に時間がかかるため、最新の JavaScript エンジンは、解釈とコンパイルの両方を組み合わせた、ジャストインタイム (JIT) コンパイルとして知られる新しい技術を使用し始めました。このプロセスでは、解釈とコンパイルを組み合わせて、コードをマシンコードに変換します。その結果、古い方法と比較して、デバッグがはるかに高速かつ簡単になります。
JavaScript のジャストインタイム (JIT) コンパイルがどのように機能するかを理解するには、JavaScript の実行コンテキストを理解する必要があります。ここで、JavaScript の実行コンテキストを理解してみましょう。
まず、次のコード例を見てください。
var a = 1; function one() { console.log(a); function two() { console.log(b); var b = 2; function three(c) { console.log(a + b + c); } three(4); } two(); } one();
1 undefined 7
コードを実行したときに、two() 関数内で宣言される前に b 変数を出力しようとしましたが、出力は未定義でした。ただし、エラーは発生しませんでした。疑問が生じます。なぜ b 変数の値が未定義になったのでしょうか?答えは JavaScript 実行コンテキストにあります。ここで、JavaScript 実行コンテキストをさらに詳しく見ていきます。
JavaScript には 2 種類の実行コンテキストがあります:
各実行コンテキストは、作成フェーズと実行フェーズという 2 つのフェーズを経ます。
JavaScript コードを実行すると、最初にグローバル実行コンテキストが発生します。このコンテキストはまず作成フェーズを通過し、そこでいくつかのことが起こります。
作成フェーズが完了すると、グローバル実行コンテキストは次のフェーズである実行フェーズに移動し、さらに多くのステップが発生します。
グローバル実行コンテキストの実行フェーズ中に参照される関数が呼び出されるとき、各関数は独自の関数実行コンテキストを作成します。グローバル実行コンテキストと同様に、関数実行コンテキストも作成フェーズを通過し、いくつかのステップが発生します。
作成フェーズが完了すると、関数実行コンテキストは実行フェーズに移動し、そこでさらに多くのステップが発生します。
他の関数内で関数が呼び出される場合、これらの関数ごとに新しい関数実行コンテキストが作成されます。各関数実行コンテキストは、作成フェーズと実行フェーズの両方を通過します。このプロセスは、別の関数内で呼び出される関数ごとに継続され、各関数はこれらのフェーズを個別に実行します。
下の図を見てみましょう。
グローバル実行コンテキストと関数実行コンテキストの両方が特定の手順を経ることがわかりました。唯一の違いは、グローバル実行コンテキストでは、最初のステップがグローバル オブジェクトを作成することであるのに対し、関数実行コンテキストでは、最初のステップは関数のパラメーター オブジェクトを作成することです。
ここで疑問が生じます: グローバル コンテキストと各関数の両方に対して実行コンテキストが作成された場合、JavaScript はこれらの実行コンテキストをどのように管理するのでしょうか?
これらのコンテキストを管理するために、JavaScript は実行スタックと呼ばれるデータ構造を使用します。実行スタックは、スタックのような方法でコンテキストを格納します。最初にグローバル実行コンテキスト、次に各関数実行コンテキストが続きます。すべての実行コンテキストがスタックに格納されると、JavaScript はスタックの先頭から順にそれらを 1 つずつ処理します。
グローバル スコープまたは関数スコープ内で let または const を使用して変数を宣言する場合、これらの変数は作成フェーズ中に変数オブジェクトに格納されず、未定義で初期化されないことに注意することが重要です。代わりに、これらの変数は実行フェーズで直接宣言され、その値が割り当てられます。
次のコード例を考えてみましょう:
var a = 1; function one() { console.log(a); function two() { console.log(b); var b = 2; function three(c) { console.log(a + b + c); } three(4); } two(); } one();
このコードを実行すると、ReferenceError が発生します。これは、変数 b を宣言する前に変数 b の値を出力しようとしており、 b は const を使用して宣言されているため、通常の変数とは異なる動作をするためです。 const または let で宣言された変数は、作成フェーズ中に変数オブジェクトに格納されません。そのため、値が割り当てられる前にアクセスしようとするとエラーが発生します。
JavaScript がどのように動作し、実行コンテキストのフェーズで何が起こるかについてのこの説明で、より明確に理解していただければ幸いです。次のレッスンでは、別の JavaScript トピックを検討します。
GitHub や Linkedin で私とつながることができます。
以上がJavaScript 実行コンテキスト – JS コードが舞台裏でどのように実行されるかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。