toc
JS基礎となる実行時メカニズム:
ec/ao/vo/go/scope/scope-chain
などの環境で実行されるようにJSコードが書かれています:
- ブラウザ
- node
- webview
- 実行コンテキストスタック 実行コンテキストスタック、スタックメモリ
- EC Execution Context 実行コンテキスト
- AO Active Object プライベートオブジェクト
- VO Variable Object 変数オブジェクト
- GO Global Object グローバルオブジェクト
- SCOPE スコープ:関数の作成時に指定。
- SCOPE-CHAIN スコープチェーン
ECStack
jsコードを実行するために、ブラウザはECStackというコード実行環境を提供する必要があります。
EC
プログラミング言語において、異なるスコープでのグローバル実行と関数実行を区別するために作成される実行コンテキスト。
VO - AO
- 各コンテキストでのコード実行中に変数が作成されることがあるため、各コンテキストには変数を格納するスペースがあります VO
- 変数オブジェクト:現在のコンテキストの変数を保持します。
- はグローバルにVO(G)
- プライベートコンテキストではAO(XXX)と呼ばれ、変数オブジェクトでもあります。
GO
ブラウザは、後の段階でJSによって呼び出される必要のあるすべてのプロパティとメソッドをGOオブジェクトに配置し、GOオブジェクトを指すグローバルなウィンドウ変数を作成します。
スタック メモリとゴミ収集メカニズム
メモリスタックの問題
let a = {n: 1};
let b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b);
- n:2}のヒープ空間がオープンされ、a.xはこの新しいヒープ空間を指します。
- その後、aのポインタは新しいヒープ空間を指すように変更されます。
- つまり、a.xは未定義であり、bは元のヒープ空間を指しています。
関数の作成と実行
関数の作成
- ヒープ・メモリをオープン
- 現在の関数のスコープの宣言
- 関数本体のコードを「文字列」としてヒープ・メモリに格納します。
- 変数から呼び出されるオブジェクトであるかのように、ヒープのアドレスをスタックに置きます。
関数の実行
関数を実行するたびに、新しいプライベートコンテキストEC(xx)が生成され、それがスタック上で実行されます。
プライベートコンテキストには、プライベート変数を保持する変数オブジェクト AO(xx) があります。
コード実行時に行うことはたくさんあります:
- スコープチェーンの初期化 <自己上的上下文,函数的作用域>
- this "を初期化します。
- ARGUMENTS実パラメータ集合の初期化
- 形式パラメータの
- 変数の昇格 ......
コード実行
実際の状況に応じて、現在のコンテキストがスタックから解放されるかどうかを判断します。
スタックメモリのサイズを確保するために、一般的に、現在の関数の実行によって生成されたコンテキストは、スタックに入力し、コードの実行が完了した後、サブコンテキストは、スタックから削除されます⇒グローバルコンテキストは、ページが開かれたときに生成され、それはまた、ページを閉じるときに解放する必要があります。
特殊なケース:現在のコンテキスト内の何かがコンテキスト以外のものに占有されている限り、現在のコンテキストを解放することはできません。
スコープチェーン検索メカニズム:
- コード実行では、ある変数に出会ったとき、まずそれが自分のプライベート変数かどうかを調べます。自分のプライベート変数であれば、すべての操作はプライベート操作です。
- もしそれが自分のプライベート変数であれば、すべての操作はプライベート操作になります。もしそれがプライベート変数でなければ、スコープチェーンに従って上位のコンテキストを探します。EC(G)を見つけるまで探し続けてください。
ブラウザのゴミ収集メカニズム
スタック・メモリ
- 一般的に、関数の実行が終了すると、その結果生成されたコンテキストはスタックから解放されます。
- 特殊なケース: 現在のコンテキストの一部のコンテンツは、コンテキストの外側のものによって占有されており、現時点ではスタックから解放できません。
- グローバルコンテキスト:ページを読み込むことで作成され、ページが閉じられたときにのみ解放されます。
ヒープメモリ:ブラウザのゴミ収集メカニズム
- 参照カウント:場合によってはカウントに混乱が生じ、メモリが解放されないことがあります。
- 参照の検出:ブラウザはアイドル時にすべてのヒープメモリを順番に検出し、何も占有されていないメモリを解放してメモリを最適化します。
管理対象メモリの手動解放
実際には、単に占有されていない
問題
質問1
var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
- グローバル実行コンテキストEC
- プライベート実行コンテキスト
- EC(func).
スコープの連鎖 スコープの連鎖 スコープの連鎖 スコープの連鎖
<EC(func), EC(G)>
- EC(anonymous1)
ロールチェインのスコープ
<EC(anonymous1), EC(func)>
- EC(func).
スコープの連鎖 スコープの連鎖 スコープの連鎖 スコープの連鎖
解析
- EC(func)のx = 3はEC(func)の形式パラメータxに影響します。
- EC(anonymous1)のx = 2はEC(func)のxに影響しますが、EC(anonymous1)はxを持たないので、2が出力されます。
- 最後のログは EC(G) の x = 1 を表示します。
質問2
var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
var x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
- で宣言されているEC
- これはEC(FUNC)で宣言されています。
<EC(anonymous1), EC(FUNC)>
したがって、スコープの連鎖を通して、x = 2 が func の形式パラメータ x を変更することがわかります。