Javascriptの基本:スコープチェーン
スコープチェーン(scope chain)という言葉がある。
ここでいうスコープとは、「有効範囲」と言ったらいいかもしれない。よく「変数のスコープ」とか、「xxxのスコープ」とかいう言い方をするが、これらは、それぞれ「変数の有効範囲」、「xxxの有効範囲」という意味と考えればいい。
javascriptには可視性修飾子(javaでいうprivateとかpublicとか)がないので、「変数のスコープ」というと
- グローバルスコープ
- ローカルスコープ
の2種類だけが存在する。(これは、PHPなんかと同じ)
話がわき道にそれるようだが、javascriptは「オブジェクトの入れ子(マトリューシュカみたいな感じ)」になっている。
一番大きいオブジェクトがwindowオブジェクト、scriptタグの直下に関数などのオブジェクトxxxを作成すれば、「windowオブジェクト内のxxxオブジェクト」、そのまた下位にオブジェクトyyyをつくれば、「windowオブジェクト内のxxxオブジェクト内のyyyオブジェクト」となる。
ちなみに、HTMLタグでくくられる文書(DOMオブジェクト)は、windowオブジェクト内のdocumentオブジェクト内に存在する。
varによって変数が宣言されると、その変数は、
それを含む最小のオブジェクト
に所属することになり、そのオブジェクト内からのみ参照が可能になる。
これが、ローカル(局所的)変数の意味となる。
グローバルスコープの変数は、名前の通り、
どのオブジェクトからでも参照できる変数
である。これと同時に、
windowオブジェクトに属するローカル変数
である。
なんで、こんな回りくどい言い方をするかというと、javascriptでは、
下位のオブジェクトから変数を参照するとき、そのオブジェクトに変数が定義されていなければ、上位のオブジェクトにさかのぼって探しに行く。
という機構が存在して、グローバル変数も、この機構によって「全てのオブジェクトから参照できる変数」になっているためである。
この機構のことを「スコープチェーン」という。
前置きが長くなってしまったが、サンプルを見た方が分かりやすいかと思う。
// グローバル変数=windowオブジェクト var prop1 = "global scope"; // --- (1) // 関数オブジェクト var test = function(){ // --- (2) var prop1 = "test_func scope"; // --- (3) // 関数オブジェクトの中の関数オブジェクト var test1 = function(){ // --- (4) var prop1 = "test1_func scope"; // --- (5) alert(prop1); // --- (6) } test1(); return; };
というスクリプトがあって、イベントによってtest1()が実行されるとする。
このサンプルでは、
windowオブジェクト ==> testオブジェクト ==> test1オブジェクト
という入れ子ができあがっていて、それぞれのオブジェクト内に、prop1という変数が定義されている。
test()がよばれると、test1((4)式)が実行されるが、test1内の(6)式はprop1という変数を参照している。
上のスクリプトをそのまま実行すると「test1_func scope」という文字列がalertボックスに表示される。ここで、(5)式をコメントアウトすると、(上位オブジェクトであるtestオブジェクト内を検索して)「test_func scope」が表示される。さらに、(3)式をコメントアウトすると、(上位オブジェクトであるwindowオブジェクト=グローバル変数を検索して)「global scope」と表示される。