いままでJavaScriptのクロージャについて、何となくで使用していました。
きちんと理解したいと思い、今回まとめていきます。
クロージャとは
そもそもクロージャとは何でしょうか。
クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。言い換えれば、クロージャは関数にその外側のスコープにアクセスする機能を提供します。JavaScript では、クロージャは関数が作成されるたびに、関数作成時点で作成されます。
MDN web docs より
。。。
なんだかよく分かりませんね。
実際にコードを見て理解を深めましょう。
クロージャの例と解説
では実際のクロージャの例を確認し、
深堀していきましょう。
コード例
通常の関数の場合、
呼び出される度に変数が初期化されてしまいます。
function countUp() {
let count = 0;
count += 1;
console.log(count);
}
countUp(); // 1
countUp(); // 1
countUp(); // 1
一方、下記はどうでしょうか。
function countUp() {
let count = 0;
function add() {
count += 1;
return count;
}
return add;
}
const counter = countUp();
counter(); // 1
counter(); // 2
counter(); // 3
変数count
の値が、呼び出すたびに加算されていることがわかります。
関数内で特定の変数を参照し続けることで、
関数が状態を保つことのできる仕組み。
これがクロージャです。
コード解説
このコードでは、クロージャの概念を利用して、関数内の変数を外部から直接アクセスできない形で保持しつつ、関数が実行される度にその変数を変更できるようにしています。
次のような流れで、count
の値が保持されます。
-
関数
countUp()
が呼び出される
countUp()
が呼び出されると、まずローカル変数count
が作成され、初期値0が代入される。 -
関数
add()
が生成される
countUp()
内で関数add()
が定義されます。
この関数add()
はcount
を1増やして返す役割を持っているが、この時点でcount
への参照が保存される。 -
クロージャが生成される
countUp()
はadd()
を返す。
このとき、count
は通常であればcountUp()
のローカル変数として破棄されるはずだが、add()
がcount
を参照しているためメモリ上に残り続ける。
これによりadd()
はcount
のスコープを閉じ込めた状態(クロージャ)となる。 -
変数
counter
としてadd()
が使用される
const counter = countUp()
とすることで、counter
はadd()
を参照するようになる。
これにより、counter()
が呼ばれる度にcount
は1増加し、最新の値を保持し続ける。
関数のスコープが単純に破棄されるのを防ぎ、参照がある限りスコープを保持します。
従って、クロージャを通じてアクセスされる変数は関数の呼び出し後もメモリ上に残り、再度呼び出されたときに同じ値にアクセスできるようになっています。
まとめ
クロージャは、関数が定義された時点でのスコープを閉じ込めた状態(=close)を保持するもののようです。
クロージャを使用することで、カプセル化によるデータの隠蔽や、状態の管理などで効果を発揮するのかなと思いました。
それでは。
参考文献