スコープチェーンについて

javascript

スコープチェーン概要

javascriptを理解する上で重要な考え方としてスコープチェーンという考え方があります。

javascriptでの変数のスコープは、グローバル変数ではプログラム全体で有効になり、
ローカル変数は宣言された関数と、その関数内でネストされた関数内で有効になります。

実際の例として、以下のようなコードを書いて実行してみます。

//グローバル変数
var test = "1";
console.log("グローバル変数 : " + test);

function scope()
{
	//ローカル変数
	var test = "2";
	console.log("ローカル変数1 : " + test);
	
	function nest()
	{
		//ネストされた関数内のローカル変数(再定義は無し)
		console.log("ネスト内のローカル変数 : " + test);
		
		//関数内のローカル変数の値を返す
		return test;
	}
	
	//このタイミングで、関数から返された「3」を返す
	return nest();
}

console.log("関数呼び出し : " + scope());
console.log("グローバル変数 : " + test);

実行した結果は次のようになります。

グローバル変数 : 1
ローカル変数1 : 2
ネスト内のローカル変数 : 2
関数呼び出し : 2
グローバル変数 : 1

先ほどの「ローカル変数は宣言された関数と、その関数内でネストされた関数内で有効」ということが上記の出力結果の「ネスト内のローカル変数 : 2」という出力結果になることで、理解できます。

上記の例のように、関数内で変数を宣言する場合や、グローバル変数を宣言する場合、
そのコード(ここでは変数の宣言)に関連づけられたスコープチェーンが存在します。

スコープチェーンはそのコードのに対してスコープ内で変数を定義するオブジェクトのリストと言えます。

ローカル変数のスコープチェーン

ローカル変数aを宣言する際、次のような処理がされます。

・変数aのチェーンの先頭を調べる
・aというプロパティを持つ場合、その値が定義される
・もし、プロパティを持たなかった場合、チェーンの次のオブジェクトを探す
・次のオブジェクトでaというプロパティがあれば、その値が定義される
・もし、なければ、同様にチェーンの次のオブジェクトを探す
・最終的にプロパティが見つからなければ、ReferenceErrorとなる

トップレベルのグローバル変数のスコープチェーン

ローカル変数ではなく、トップレベルのグローバル変数の場合は次のようになります。

・グローバル変数は一つだけ定義される
・関数1つに2つのスコープチェーンが存在する(1つ目のスコープチェーンは関数の引数、ローカル変数、2つ目はグローバルオブジェクト)
・ネストされた関数の場合、3つ以上のスコープチェーンになる
・ネストされた関数が定義された時、スコープチェーンが保持される
・ネストされた関数が呼び出された時、オブジェクトが生成される
・ローカル変数が保存される
・上記の生成されたオブジェクトをスコープチェーンに追加する
・関数呼び出しのスコープチェーンを表す新たなスコープチェーンを生成

簡易的に書きましたが、次のネストされた関数の場合と合わせて、全体像を理解することがポイントになります。

ネストされた関数の場合

ネストされた関数の場合は、次のような動きになります。

その側の関数が呼び出されるたびに内側の関数が再び定義され、
外側の関数の呼び出しごとに、スコープチェーンが異なって動作します。

このスコープチェーンが異なって動作する。という考え方がjavascriptのクロージャの考え方につながってくるので重要です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です