Last active
May 24, 2020 05:26
-
-
Save kajirikajiri/6d93e3dda22d883e6a2a0be422824165 to your computer and use it in GitHub Desktop.
JavaScriptの実行コンテキストと実行スタック
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* プログラム内に存在できるグローバル実行コンテキストは1つだけです。 | |
たしかに1つだ。他にもあるかもと思ってた | |
* 評価関数の実行コンテキスト - eval関数内でのコードの実行には独自の実行コンテキストがありますが、JavaScript開発者が頻繁に使用evalすることはないため、ここでは説明しません。 | |
こんなのあるのか | |
* 実行スタックは、他のプログラミング言語では「コールスタック」とも呼ばれ、コードの実行時に作成されるすべての実行コンテキストを格納するために使用されるLIFO(後入れ先出し)データ構造を持つスタックです。 | |
LIFO(後入れ先出し) | |
* JavaScriptエンジンは、最初にスクリプトに遭遇すると、グローバル実行コンテキストを作成し、それを現在の実行スタックにプッシュします。エンジンは関数呼び出しに遭遇すると、関数の新しい実行コンテキストを作成し、それをスタックの一番上にプッシュします。 | |
遭遇した順にプッシュ | |
* エンジンは、実行コンテキストがスタックの最上位にある関数を実行します。この関数の実行が終了すると、実行コンテキストがスタックからポップされ、制御フローは現在のスタックの次のコンテキストに到達します。 | |
終わったらポップ | |
```javascript | |
let a = 'Hello World!'; | |
function first() { | |
console.log('Inside first function'); | |
second(); | |
console.log('Again inside first function'); | |
} | |
function second() { | |
console.log('Inside second function'); | |
} | |
first(); | |
console.log('Inside Global Execution Context'); | |
``` | |
https://user-gold-cdn.xitu.io/2018/9/20/165f539572076fe3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1 | |
* 上記のコードの実行コンテキストスタック。 | |
* 上記のコードがブラウザーに読み込まれると、JavaScriptエンジンはグローバル実行コンテキストを作成し、それを現在の実行スタックにプッシュします。first()関数呼び出しに直面すると、JavaScriptエンジンは実行コンテキストの新しい関数を作成し、現在の実行のスタックの最上位に配置します。 | |
ブラウザーに読み込まれるとグローバル実行コンテキストを作成。 | |
* ときにfirst()内部の機能を呼び出すsecond()機能を、JavaScriptエンジンはするsecond()新しい実行コンテキストを作成して、現在実行中の関数のスタックの一番上にそれを置きます。ときにsecond()関数が完了し、その実行コンテキストスタックは、現在からポップアップ表示されます、および制御フローは、次の実行コンテキストになる、すなわち、first()実行コンテキスト機能。 | |
関数呼び出しに達すると、関数をpush。内部に関数があればさらにpush。完了した順にpop. | |
* ときにfirst()終了、それがスタックからコンテキストポップを実行、制御の全体の流れは、実行コンテキストに達します。すべてのコードが実行されると、JavaScriptエンジンは現在のスタックからグローバル実行コンテキストを削除します。 | |
最後にグローバル実行コンテキストを削除 | |
* 実行コンテキストを作成するには? | |
* これまで、JavaScriptが実行コンテキストを管理する方法を見てきましたが、JavaScriptエンジンが実行コンテキストを作成する方法を理解しましょう。 | |
* 実行コンテキストを作成するには、1)作成ステージと2)実行ステージの 2つのステージがあります。 | |
気にならなかった。知れるなら知りたい。 | |
```javascript | |
ExecutionContext = { | |
ThisBinding = <this value>, | |
LexicalEnvironment = { ... }, | |
VariableEnvironment = { ... }, | |
} | |
``` | |
thisバインディング | |
LexicalEnvironmentコンポーネント | |
VariableEnvironmentコンポーネント | |
LexicalEnvironment | |
* 簡単に言えば、字句環境は、識別子と変数のマッピングを保持する構造です。(ここで、識別子は変数/関数の名前を指し、変数は実際のオブジェクト(関数オブジェクトと配列オブジェクトを含む)またはプリミティブ値への参照です)。 | |
変数関数の名前、関数オブジェクト、配列オブジェクト、プリミティブ値への参照 | |
例えば、つぎのスニペットを考えてみると | |
```javascript | |
var a = 20; | |
var b = 40; | |
function foo() { | |
console.log('bar'); | |
} | |
``` | |
lexicalEnvironmentはこのようになる | |
```javascript | |
lexicalEnvironment = { | |
a: 20, | |
b: 40, | |
foo: <ref. to foo function> | |
} | |
``` | |
lexicalEnvironmentには2つのコンポーネントがある | |
Environment Record | |
変数と関数宣言が保存される実際の場所です。 | |
Reference to the outer environment | |
その親のlexicalEnvironment(スコープ)にアクセスできることを意味します。 | |
外部のlexicalEnvironmentにアクセスできることを意味します。つまり、JavaScriptエンジンは、現在のlexicalEnvironmentで変数が見つからない場合、外部環境内の変数を検索できます。 | |
lexicalEnvironmentには2つのタイプがある | |
GlobalExectionContext | |
Type: "Object"のEnvironmentRecorder | |
FunctionExectionContext | |
Type: "Declarative"のEnvironmentRecorder | |
``` | |
const person = { | |
name: 'peter', | |
birthYear: 1994, | |
calcAge: function() { | |
console.log(2018 - this.birthYear); | |
console.log(outer) | |
} | |
} | |
person.calcAge(); | |
// 'calcAge'が// 'person'オブジェクト参照で呼び出されたため、 'this'は 'person'を参照します | |
// つまり、2018 - 1994になります | |
const calculateAge = person.calcAge; | |
calculateAge(); | |
//オブジェクト参照が指定されていないため、「this」はグローバルウィンドウオブジェクトを参照します// まじか | |
``` | |
```javascript | |
GlobalExectionContext = { | |
LexicalEnvironment:{ | |
EnvironmentRecord:{ | |
Type: "Object"、 | |
// Identifier bindings go here | |
} | |
outer:<null>、 // そういうことかglobalのthisにはouterがない | |
this:<global object> | |
} | |
} | |
FunctionExectionContext = { | |
LexicalEnvironment:{ | |
EnvironmentRecord:{ | |
Type: "Declarative"、 | |
// Identifier bindings here here | |
} | |
outer:<グローバルまたは外部関数環境参照>、 // これ呼べんの? | |
this:<関数の呼び出し方法に依存> // こいつがthisでよべんなら、outerで呼べんる? // よべなかったは // 無理そう https://stackoverflow.com/questions/2264037/access-outer-this-in-javascript-sort-method // 方法としては、外側で変数にthisを代入、もしくは、arrow関数を使う。それか.bind(this)でバインドする | |
} | |
} | |
``` | |
Variable Environment | |
ES6では、lexicalEnvironmentComponentとEnvironmentVariableComponentの違いは前者は変数と関数宣言(let及びconst)バインディングの格納に使用される。後者はvar変数バインディングの格納に使用される | |
上記を理解するためのサンプル | |
```javascript | |
let a = 20; | |
const b = 30; | |
var c; | |
function multiply(e, f) { | |
var g = 20; | |
return e * f * g; | |
} | |
c = multiply(20, 30); | |
``` | |
実行コンテキストはこうなる | |
``` | |
GlobalExectionContext = { | |
ThisBinding: <Global Object>, | |
LexicalEnvironment: { | |
EnvironmentRecord: { | |
Type: "Object", | |
a: < uninitialized >, | |
b: < uninitialized >, | |
multiply: < func > | |
} | |
outer: <null> | |
}, | |
VariableEnvironment: { | |
EnvironmentRecord: { | |
Type: "Object", | |
c: undefined, | |
} | |
outer: <null> | |
} | |
} | |
FunctionExectionContext = { | |
ThisBinding: <Global Object>, | |
LexicalEnvironment: { | |
EnvironmentRecord: { | |
Type: "Declarative", | |
// 在这里绑定标识符 | |
Arguments: {0: 20, 1: 30, length: 2}, | |
}, | |
outer: <GlobalLexicalEnvironment> | |
}, | |
VariableEnvironment: { | |
EnvironmentRecord: { | |
Type: "Declarative", | |
// 在这里绑定标识符 | |
g: undefined | |
}, | |
outer: <GlobalLexicalEnvironment> | |
} | |
} | |
``` | |
a,b(let,const)はどの値にも関連付けられていないが、c(var)はundefined。 | |
これが、varに宣言より前にアクセスできる理由。巻き上げ。変数宣言の昇格 | |
実行フェーズ | |
これは記事全体の中で最も単純な部分です。この段階で、これらすべての変数の割り当てが完了し、最後にコードが実行されます。 | |
注 -実装フェーズでletは、変数の値を見つけるためにソースコードで宣言されたJavaScriptエンジンの実際の場所でない場合は、割り当てられundefinedます。 | |
https://juejin.im/post/5ba32171f265da0ab719a6d7 | |
https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment