ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript 呼び出しスタックの謎を解く: コードが実際にどのように実行されるか
JavaScript 呼び出しスタック がどのように機能するかということは、すべてのフロントエンド開発者がそのキャリアの中で少なくとも一度は尋ねたことがあることであり、私の意見では、これは誰もが知っている質問ではありません。ほとんどの場所で答えが得られますが、その答えは必ずしも明確ではなく、理解しやすいものではありません。だからこそ、この記事でこのトピックを取り上げることにしました。
最初から始めましょう。 JavaScript エンジンはコードを 1 行ずつ同期的に実行します。関数が実行されるたびに、実行コンテキスト (メモリ内のスペース のみが存在するすべてのスコープ付きプロパティを保存します) が作成されます。その関数内) そして関数を呼び出しスタックに追加します.
JavaScript はスタックの最上位にある関数のコードのみを実行し、関数が終了してその値を返すと、エンジンは呼び出しスタックから関数を削除します そして次の作業を開始します。
コール スタックが空である場合、JavaScript エンジンは次のグローバル コンテキストでコードの実行を継続します、または同様に、JavaScript ファイルのルート であり、どの関数にも属しません。
行ごとにいくつかの例を見てみましょう:
const num1 = 2; const num2 = 5; function sum(a, b){ return a + b; } const result= sum(num1, num2); console.log(result) // 7これは、2 つの定数 (num1 と num2) を定義し、2 つの数値を合計して合計の結果を返す関数
sum を定義する非常に単純なコードです。最後に、定数 result が作成され、引数 num1 と num2 を指定して sum を実行した 結果 がそれに代入されます。次に、結果の値がコンソールに出力されます。
これまでの説明が単純すぎる、または複雑すぎて何も説明されていないと思われる場合は、ご容赦ください。興味深い内容に近づいています。
JavaScript エンジンが何をしているのかを一行ずつ見てみましょう。最初の行では、エンジンはラベル num1 を作成し、値 2 を メモリに保存します。
const num1 = 2;num2
に対して同じことを行います。ラベル num2 を作成し、値 5 をメモリに保存します。
const num2 = 5;グローバル スコープ
内の誰かが num2 の値を要求するたびに、エンジンがラベルを変更して値 5 を設定するということです。代わりに。 次の行に進みましょう。次の行は
関数 sum です。エンジンはどうなると思いますか?関数を実行しようとしているのか、それとも呼び出しスタックに追加しようとしているのでしょうか? いいえ! エンジンが行うことは、sum という名前の新しいラベルを保存し、括弧内のコードをメモリに保存することです。または、同じことは、関数定義を保存し、それをsumラベルに割り当てます。
function sum(a, b){ return a + b; }視覚的に確認できる
場合は、次のようになります。
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
興味深い行です。 JavaScript エンジンが次の行に到達すると、ラベル result を作成しますが、この時点では、ラベル にどのような値を割り当てる必要があるかまだわかりません。 >値は関数を実行した結果です。そのため、まず関数を実行し、関数が行う必要があることをすべて実行して、戻り値から結果を取得します。
この時点で、エンジンは
const result= sum(num1, num2);し、また
メモリ内の新しいスペースである新しい実行コンテキストも作成します。 JavaScript は、グローバル コンテキストと衝突することなく、引数の値と関数内の他のすべてのプロパティを保存できます。
First of all, the engine creates in memory the labels a and b which are the names given to the parameters, and it assigns the value of the arguments 2 and 5 respectively.
If we could see the memory at this specific moment, we would see something like this:
Label name | Value in memory |
---|---|
a | 2 |
b | 5 |
return | 2 + 5 = 7 |
In this case, the function is really simple and only returns the value of the sum between a and b, so the engine substitutes the parameters with the values of the arguments and returns the value to the global execution context. Finally, the function is removed from the call stack, and only the global context remains.
Call stack |
---|
Global |
At this point, the result of the function is assigned to the label result and we can print the value on console with the console log.
Let's take a look at how the global memory looks now:
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
result | 7 |
Did you noticed? the label result has a value of 7? and also sum still has the function definition inside.
Let's take a look at the next code:
const num1 = 2; const num2 = 5; function sum(a, b){ return a + b; } const result= sum(num1, num2); console.log(result) // 7 function sumThreeNumbers = (x,y,z) => { return sum(x, y) + z } const result2 = sumThreeNumbers(4,6,2) console.log(result2) // 12
The main difference is that now we have a new sumThreeNumbers function and we are creating a new result2 constant and assigning the value of running the function sumThreeNumbers with the arguments, 4, 6 and 2.
Let's take a look at how the call stack works when we run nested functions.
If we jump to the line when we define the constant result2 the global memory would look something like this:
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
result | 7 |
sumThreeNumbers | function definition |
Just as on the previous example, the JavaScript engine doesn't know what value to assign to the label result2, to get the value, first needs to execute the function sumThreeNumbers with the arguments. The function is added to the call stack, and a new execution context is created. The execution context would look like this:
Label name | Value in memory |
---|---|
x | 4 |
y | 6 |
z | 2 |
So the first thing that JavaScript does is create the parameter labels and assign the value provided by the arguments.
Now let's take a look at our call stack
Call stack |
---|
sumThreeNumbers |
Global |
As you can see, the call stack only has the sumThreeNumbers item (apart from the global context that is always present).
To be able to get the result value, the function sum needs to be executed first, so the engine will add the function to the call stack and create a new execution context for the sum function.
Call stack |
---|
sum |
sumThreeNumbers |
Global |
As the sum function is on top of the call stack, Javascript needs to run sum first to be able to continue running sumThreeNumbers.
This is how it's going to look the execution context for the function sum:
Label name | Value in memory |
---|---|
a | 4 |
b | 6 |
return | 4 + 6 = 10 |
ご存知のとおり、_10 _が返され、呼び出しスタックから削除されます
Call stack |
---|
sumThreeNumbers |
Global |
JavaScript は sumThreeNumbers の実行を継続し、実行コンテキストは次のようになります:
Label name | Value in memory |
---|---|
x | 4 |
y | 6 |
z | 2 |
return | 10 + 2 = 12 |
値 12 が返され、呼び出しスタックから削除されます。
Call stack |
---|
Global |
その後、値 12 がプロパティ result2 に割り当てられ、値 12 がコンソールに表示されます。
この投稿が、JavaScript コールスタックの仕組みを理解するのに役立つことを願っています。もしそうなら、コメントや「いいね!」を残してください。次の記事でお会いしましょう!
以上がJavaScript 呼び出しスタックの謎を解く: コードが実際にどのように実行されるかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。