JavaScript クロージャ


JavaScript の変数はローカル変数またはグローバル変数にできます。

プライベート変数にはクロージャを使用できます。


グローバル変数

関数は関数内部で定義された変数にアクセスできます。例:

サンプル

function myFunction() { var a = 4; return a * a; }

試してみる »

関数は関数外部で定義された変数にもアクセスできます。例:

サンプル

var a = 4; function myFunction() { return a * a; }

試してみる »

後者のサンプルでは、aはグローバル変数です。

Webページでは、グローバル変数は window オブジェクトに属します。

グローバル変数はページ上のすべてのスクリプトで使用できます。

最初のサンプルでは、aはローカル変数です。

ローカル変数は、それを定義した関数の内部でのみ使用できます。他の関数やスクリプトコードからは利用できません。

グローバル変数とローカル変数は、たとえ名前が同じでも、それらは2つの異なる変数です。一方を変更しても、もう一方の値には影響しません。

Note 変数を宣言するときにvarキーワードを使用しない場合、関数内で定義されていても、その変数はグローバル変数になります。


変数のライフサイクル

グローバル変数のスコープはグローバルです。つまり、JavaScriptプログラム全体を通して、グローバル変数はどこでも利用できます。

一方、関数内部で宣言された変数は、関数内部でのみ有効です。これらの変数はローカル変数であり、スコープは局所的です。関数のパラメータも局所的であり、関数内部でのみ有効です。


カウンターのジレンマ

いくつかの数値をカウントしたいとします。そして、そのカウンターがすべての関数で使用できるとします。

グローバル変数を使用して、関数でカウンターをインクリメントできます:

サンプル

var counter = 0; function add() { return counter += 1; } add(); add(); add(); //カウンターは現在 3

試してみる »

カウンターの値は add() 関数の実行時に変化します。

しかし問題は、ページ上のどのスクリプトでも、add() 関数を呼び出さなくてもカウンターを変更できることです。

関数内でカウンターを宣言すると、関数を呼び出さない限りカウンターの値を変更できません:

サンプル

function add() { var counter = 0; return counter += 1; } add(); add(); add(); //本来は 3 を出力したいのですが、期待に反して、出力されるのはすべて 1 です!

試してみる »

上記のコードは正しく出力されません。add() 関数を呼び出すたびに、カウンターが 1 に設定されるからです。

JavaScript のネスト関数でこの問題を解決できます。


JavaScript ネスト関数

すべての関数はグローバル変数にアクセスできます。

実際、JavaScript では、すべての関数はその1つ上のスコープにアクセスできます。

JavaScript はネスト関数をサポートしています。ネスト関数は1つ上の関数の変数にアクセスできます。

このサンプルでは、ネスト関数plus()は親関数のcounter変数にアクセスできます:

サンプル

function add() { var counter = 0; function plus() {counter += 1;} plus(); return counter; }

試してみる »

外部からplus()関数にアクセスできれば、カウンターのジレンマを解決できます。

また、counter = 0が一度だけ実行されるようにする必要があります。

クロージャが必要です。


JavaScript クロージャ

関数の自己呼び出しを覚えていますか? その関数は何をするでしょうか?

サンプル

var add = (function () { var counter = 0; return function () {return counter += 1;} })(); add(); add(); add(); //カウンターは 3

試してみる »

サンプル解説

変数addは関数の自己呼び出しの戻り値を受け取ります。

自己呼び出し関数は一度だけ実行されます。カウンターを 0 に設定し、関数式を返します。

add 変数は関数として使用できます。素晴らしい点は、1つ上の関数スコープのカウンターにアクセスできることです。

これは JavaScript のクロージャと呼ばれます。これにより、関数がプライベート変数を持つことが可能になります。

カウンターは匿名関数のスコープによって保護され、add メソッドを通じてのみ変更できます。

Note

クロージャはプライベート変数を保護するメカニズムです。関数の実行時にプライベートスコープを作成し、内部のプライベート変数を外部からの干渉から保護します。

直感的に言えば、クロージャは破棄されないスタック環境のようなものです。

その他の拡張