2020-5-22
- 静的スコープ: ある変数がどの値を参照するかは静的に決まる
- メモリ管理の仕組み: 参照されなくなったデータはガベージコレクションにより解放される
クロージャーとはこの2つの仕組みを利用して、関数内から特定の変数を参照し続けることで関数が状態を持てる仕組みのことを言います。
最初にクロージャーの例として紹介したcreateCounter
関数の例を改めて見てみましょう。
const createCounter = () => {
let count = 0;
return function increment() {
// `increment`関数は`createCounter`関数のスコープに定義された`変数`count`を参照している
count = count + 1;
return count;
};
};
// createCounter()の実行結果は、内側で定義されていた`increment`関数
const myCounter = createCounter();
// myCounter関数の実行結果は`count`の評価結果
console.log(myCounter()); // => 1
console.log(myCounter()); // => 2
つまり次のような参照の関係がmyCounter
変数とcount
変数の間にはあることがわかります。
myCounter
変数はcreateCounter
関数の返り値であるincrement
関数を参照しているmyCounter
変数はincrement
関数を経由してcount
変数を参照しているmyCounter
変数を実行した後もcount
変数への参照は保たれている
myCounter
->increment
->count
count
変数を参照するものがいるため、count
変数は自動的に解放されません。 そのためcount
変数の値は保持され続け、myCounter
変数を実行するたびに1ずつ大きくなっていきます。
このようにcount
変数が自動解放されずに保持できているのは「increment
関数内から外側のcreateCounter
関数スコープにあるcount
変数を参照している」ためです。 このような性質のことをクロージャー(関数閉包)と呼びます。クロージャーは「静的スコープ」と「参照され続けている変数のデータが保持される」という2つの性質によって成り立っています。
クロージャーは、変数が参照する値が静的に決まる静的スコープという性質とデータは参照されていれば保持されるという2つの性質によって成り立っています。