#クロージャー
クロージャーとはレキシカルスコープの変数を関数が使用している状態のことを指します。イラストで確認してみましょう
function fn1() {
let b =1;
function fn2() {
console.log(b);
}
fn2();
}
fn1();
このように関数が多階層で定義されている時に、関数fn2がそのレキシカルスコープである変数bを参照しています。このこの状態をクロージャーと表現します。このクロージャーを用いた実装ケースも確認しましょう。
###プライベート変数の定義
まずinvrement関数というものを用意し、この関数が呼ばれた際にカウントを1つずつ加算する仕組みを作ってみましょう。
let num = 0;
increment();
increment();
increment();
function increment() {
num = num +1;
console.log(num);
}
これで1,2,3と出力できます。ただこのままではnumがソースコードのどこからでも書き換えることができてしまします。例えば以下のようにどこかでnumの値を初期化してしまった(書き換えた)場合出力される値が被ってしまい期待した挙動が取れないケースがあります。
let num = 0;
increment();
increment();
increment();
function increment() {
num = num +1;
console.log(num);
}
num = 0;
increment();
そこで、クロージャーを用いて関数の内部には変数をもちながらも外部からはアクセスできないようにしましょう。
まず、incrementという関数をincrementFactoryと書き換えます。このincrementFactory内にnumの初期化、及びincrement関数を記述し、incrementFactoryの戻り値としてincrement関数を設定します。このようにJavaScriptでは関数も戻り値として設定することができます。
function incrementFactory() {
let num = 0;
function increment() {
num = num +1;
console.log(num);
}
return increment
}
const increment = incrementFactory();
increment();
最後に戻り値をincrementという変数に格納し実行します。この時incrementFactoryの中で関数incrementの中で使用していることになるので、関数incrementはnumへの参照を保持している状態でincrementFactoryから返却することになります。ちなみに関数の実行は関数名のあとに()をつけます。
###動的な関数生成
静的な関数との違いは関数を生成する関数に引数を設定し、呼び出し時に参照する値を設定できる点になります。
function addNumberFactory(num) {
function addNumber(val) {
return num + val;
}
return addNumber;
}
const add5 = addNumberFactory(5);
const result = add5(10);
console.log(result);
addNumberFactory(num)の引数であるnumへの参照を呼び出し時点で保持します。
##参考
Udemy: 【JS】ガチで学びたい人のためのJavaScriptメカニズム