無料Wikiサービス | デモページ
Linuxなどのメモ書き

JavaScript 実行コンテキスト


O'REILLY JavaScript 第3版 のスコープあたりを読んでいて混乱してきたので、整理がてらメモ。

1.オブジェクト

グローバルオブジェクト
グローバル変数がオブジェクトのプロパティとして格納される。常に1つだけ存在する。

Callオブジェクト
関数の実行中、変数や引数がオブジェクトのプロパティとして格納されている。関数を実行する度に作成される。

2.実行コンテキスト

関数を実行するたびに新しいコンテキストを作成する。スタック構造をしており、スタックのTopが現在の実行コンテキスト。
(スタックフレームのようなもの)

  • 関数外部(グローバル)のJavascriptコード実行時の実行コンテキストはグローバルオブジェクト
  • 関数内部のJavascriptコード実行時の実行コンテキストは関数実行時に作成されたCallオブジェクト

実行コンテキスト==グローバル/Callオブジェクトっぽい書きかたがしてある。

3.スコープチェーン

スコープチェーンはグローバル/Callオブジェクトのリスト。変数を参照する際に、スコープチェーンの末端から順番に探される。リストのトップはグローバルオブジェクトとなる。

実行コンテキスト毎に1つのスコープチェーンが存在する。関数が実行されて新しいコンテキストが作られるとスコープチェーンも作られる。

4.静的スコープ

関数実行時に使用するスコープチェーンは関数定義時に決定される(関数が定義された時点のスコープチェーンが使用される)。

最も基本的なケースであるグローバル領域で関数を定義した場合は、関数定義時はグローバルオブジェクト一つのスコープチェーンであるため、これを使用することになる。このチェーンに呼び出した関数のCallオブジェクトが追加される。

以下に例を示す。

4.1 グローバル領域で関数定義をした場合

x=1;
function f() {var y=2;g();}
function g() {var z=3;}
f();

(1) f(),g()定義時のスコープチェーン
+------+
| x=1 | Global Obj.
+------+
f(),g()にはこのスコープチェーンが使用される。


(2) f()が呼び出されると...
+------+
| x=1 | Global Obj.
+------+ <--+
|
+------+ ---+
| y=2 | f() Call Obj.
+------+
(1)のスコープチェーンにf()を呼び出した時に作成されたCall Obj.がチェーンされる。y,xはスコープチェーンにあるので参照できるが、zは参照できない。
このあたりはCとかと同じなので問題なし。


(3)f()からg()が呼び出されると...
+------+
| x=1 | Global Obj.
+------+ <--+
|
+------+ ---+
| z=3 | g() Call Obj.
+------+
g()も(1)のスコープチェーンを使用するので、(1)にg()を呼び出した時に作成されたCall Obj.がチェーンされる。
g()から参照できるのはz,xのみ。これも問題なし。

4.2 関数領域に関数定義をした場合

x=1;
function f()
{
var y = 2;
g();
function g() {var z=3;}
}
f();

(4) g()定義時のスコープチェーン
+------+
| x=1 | Global Obj.
+------+ <--+
|
+------+ ---+
| y=2 | f() Call Obj.
+------+
f()が呼び出されて初めてg()が定義されている


(5) f()を呼び出して、f()からg()が実行されると...
+------+
| x=1 | Global Obj.
+------+ <--+
|
+------+ ---+
| y=2 | f() Call Obj.
+------+ <--+
|
+------+ ---+
| z=3 | g() Call Obj.
+------+
g()が定義された時のチェーンは(4)なので、(4)にg()呼び出し時のCall Obj.がチェーンされる。
g()からはx,y,zが参照可能。このあたりもまだ、直感的にOK。

4.3 呼び出される度に関数を返す関数

function f(x)
{
return function () {return x}
}
func1 = f(1);
func2 = f(2);
alert(func1()); <== 1と表示
alert(func2()); <== 2と表示

関数{return x}はf(x)を実行するたびに作成(定義)される。このため、f(1),f(2)で{return x}が作成された時のそれぞれのスコープチェーンは以下のようになる。

(6) f(1)でreturn xが定義されたときのスコープチェーン
+------+
| | Global Obj.
+------+ <--+
|
+------+ ---+
| x=1 | f(1) Call Obj.
+------+

(7) f(2)で{return xが定義されたときのスコープチェーン
+------+
| | Global Obj.
+------+ <--+
|
+------+ ---+
| x=2 | f(2) Call Obj.
+------+
このため、func1(),func2()を呼び出すとそれぞれ、以下のスコープチェーンになる。


(8) func1()呼び出し時のスコープチェーン
+------+
| | Global Obj.
+------+ <--+
|
+------+ ---+
| x=1 | f(1) Call Obj.
+------+ <--+
|
+------+ ---+
| | {return x} Call Obj.
+------+
(6)にfunc1()呼び出し時のCall Obj.がチェーンされる。


(9) func2()呼び出し時のスコープチェーン
+------+
| | Global Obj.
+------+ <--+
|
+------+ ---+
| x=2 | f(2) Call Obj.
+------+ <--+
|
+------+ ---+
| | {return x} Call Obj.
+------+
(6)にfunc2()呼び出し時のCall Obj.がチェーンされる。

よって、func1()では1が返り、func2()では2が返るようになる。



最終更新 2006/06/13 17:06:25 - kztomita
(2006/04/07 18:17:44 作成)