JavaScript クロージャ

❮ 前章へ 次章へ ❯

JavaScript 変数は、local または global スコープに属すことができます。

プライベート変数は、クロージャで可能にすることができます。


グローバル変数

次のように、関数は、関数内部で定義されているすべての変数にアクセスすることができます:

function myFunction() {
    var a = 4;
    return a * a;
}
Try it Yourself »

しかし、次のように関数ので定義された変数にもアクセスすることができます:

var a = 4;
function myFunction() {
    return a * a;
}
Try it Yourself »

最後の例の a は、グローバル変数です。

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

グローバル変数は、ページ内(および window 内)のすべてのスクリプトで使用(および変更)することができます。

最初の例の a は、ローカル変数です。

ローカル変数は、定義されている関数の内部でのみ使用することができます。 これは、他の関数や他のスクリプトコードからは隠蔽されます。

同じ名前のグローバル変数とローカル変数は異なる変数です。一方を変更しても、他方は変更されません。

strong>var キーワードを使わずに作成した変数は、関数内で作成した場合でも、 常にグローバルになります。


変数の寿命

グローバル変数は、アプリケーション(window / web ページ)が生きている限り生きています。

ローカル変数の寿命は短命で、関数が呼び出されたときに作成され、関数が終了すると削除されます。


カウンタのジレンマ

変数を使用して何かをカウントし、全ての関数がこのカウンタを利用できるようにしようと考えたとします。

グローバル変数と関数を使用して、カウンタを増分することができます:

var counter = 0;

function add() {
    counter += 1;
}

add();
add();
add();

// the counter is now equal to 3
Try it Yourself »

カウンタは、add() 関数を使ってのみ変更しなければなりません。

しかし、問題は add() を使わないで、ページのあらゆるところからカウンタの変更ができてしまうところです。

関数内に counter を宣言すれば、add() を呼び出さずには変更することができなくなります:

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

add();
add();
add();

// the counter should now be 3, but it does not work !
Try it Yourself »

これは正しく機能しません! add() 関数を呼び出すたびに、カウンタに 1 が設定されてしまいます。

JavaScript の内部関数を使用することで、これを解決することができます。


JavaScript 関数のネスト

すべての関数はグローバルスコープへのアクセス権を持っています。

実際に、JavaScript では、すべての関数はその「上」のスコープへのアクセス権を持っています。

JavaScript は、関数のネストをサポートしています。ネストした関数は、その「上」のスコープへのアクセス権を持っています。

この例では、内部関数の plus() は親関数の counter 変数にアクセスしています:

function add() {
    var counter = 0;
    function plus() {counter += 1;}
    plus();   
    return counter;
}
Try it Yourself »

外から plus() 関数に到達できれば、これはカウンタのジレンマを解決する可能性があります。

また、一度だけ counter = 0 を実行するための方法を見い出す必要もあります。

我々にはクロージャが必要です。


JavaScript のクロージャ

即時関数を覚えていますか?この関数は何をするのでしたでしょうか?

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

add();
add();
add();

// the counter is now 3
Try it Yourself »

例の説明

変数 add には、即時関数の戻り値が代入されます。

即時関数は、一度だけ実行されます。これは、counter にゼロ(0)を設定し、関数式を返します。

このように、add は関数になります。「素晴らしい」ところは、それが親スコープの counter にアクセスできることです。

これは、JavaScript のクロージャ と呼ばれています。 関数が "private" な変数を持つことを可能にします。

counter は、匿名関数のスコープによってプロテクトされ、唯一 add 関数を使用してのみ変更が可能です。

A closure is a function having access to the parent scope, even after the parent function has closed.


❮ 前章へ 次章へ ❯