function createCounter() {
let count = 0; // 外側の変数
return function() { // 内側の関数
count++;
return count;
};
}
let counter = createCounter();
Logger.log(counter()); // 出力: 1
Logger.log(counter()); // 出力: 2
Logger.log(counter()); // 出力: 3
というか、これですがjavaの場合はメソッド毎にデータが保持されないので、値は変わらないと思うのですが、javascriptの場合、値が順にふえていくのはどうしてですか?
クロージャとは?
クロージャとは、関数が宣言されたときのスコープ(範囲)を保持する機能のことです。JavaScriptでは、関数が別の関数内で宣言されると、その外側の関数の変数にアクセスでき、そのスコープを保持し続けます。これにより、関数が外部で実行される際にも、元のスコープの変数(この場合、count
)にアクセスし、それを操作できるのです。
具体的には、以下のように動作します:
createCounter
関数が呼び出されると、count
というローカル変数が初期化されます (let count = 0;
)。createCounter
関数は、count
にアクセスできる無名関数を返します。この無名関数は、count++
を実行することでカウントを増加させます。- 返された無名関数は、そのスコープで**
count
変数の参照を保持**します。つまり、createCounter
関数が終了した後でも、count
にアクセスし、値を操作できるのです。 counter()
を呼び出すたびに、count++
が実行され、count
の値が順に増加していきます。
JavaとJavaScriptの違い
Javaでは、メソッドが呼ばれるたびにローカル変数は再初期化され、メソッドが終了するとそのスコープの変数は破棄されます。したがって、Javaでは以下のようなコードを書いても、変数count
は毎回初期化され、値を保持し続けることはありません。
Javaでは、例えば次のように書くと、count
は毎回0からスタートします。
javaコードをコピーするpublic class Counter {
public int createCounter() {
int count = 0; // 外側の変数
count++;
return count;
}
public static void main(String[] args) {
Counter counter = new Counter();
System.out.println(counter.createCounter()); // 出力: 1
System.out.println(counter.createCounter()); // 出力: 1
}
}
JavaScriptで値が保持される理由:クロージャの仕組み
JavaScriptでは、関数内で別の関数を返すと、その外側の関数のスコープが保持されます。具体的には、以下の流れです。
createCounter
関数が実行されると、count
変数が定義されます(初期値0)。createCounter
は、count
をインクリメントする関数を返しますが、その関数は**count
のスコープを保持**します。let counter = createCounter();
により、counter
変数には、count
にアクセスできる関数が格納されます。counter()
を呼び出すたびに、そのスコープ内のcount
がインクリメントされます。
重要なのは、createCounter
が終了した後でも、count
が保持されることです。これがクロージャの効果です。
クロージャの仕組み:図解
createCounter()
呼び出しcount
変数が0
で初期化され、count++
を実行する無名関数が返される。
counter()
の呼び出しcount
変数がインクリメントされ、1
になる。counter()
の呼び出しごとに、同じcount
が保持され、値が増加する。
JavaScriptでは、このように関数が定義された時点の**スコープ(環境)**を保持することで、変数が後から呼び出された関数の中で保持され続け、更新されていくわけです。
まとめ
- クロージャとは、関数がその外側のスコープにある変数を保持し続ける仕組みのことです。これにより、
count
のようなローカル変数を外部の関数から操作することが可能です。 - Javaでは、メソッドを呼び出すたびにローカル変数は再初期化されますが、JavaScriptではクロージャにより、関数が変数のスコープを保持するため、値が保持されて更新され続けます。
この動作が、JavaScriptが関数を第一級オブジェクトとして扱い、柔軟にスコープを管理できるという強力な機能の一つです。
コメント