JavaScriptで扱う関数がオブジェクトとしての振る舞うことを、高階関数や即時実行関数式などを扱ってみてきました。
ここでは、これらの関数の性質を利用してクロージャについてみて行こうと思います。
クロージャは簡単に表現すると、ローカル変数を参照している関数内関数ということができますが、具体的なコードで見ていく方がわかりやすいと思いますので、早速見ていきましょう。
クロージャの基本的な操作
クロージャを使った具体的なコードを書いてみます。世の中には20●●年問題と言われている転換点に関する話題のものがいくつかありますが、それと年齢計算を使って次のようなコードを書いてみました。(ちょっと不恰好なコードですけども)
function turning(turningYear) {
var a = '年の猶予があります。';
return function(birthYear) {
var age = turningYear - birthYear;
console.log((turningYear - 2019) + a + 'その時は' + age + '才です。');
};
}
クロージャとして関数turning()を定義しています。引数にturningYearをとって転換の年と言われる西暦を渡します。ブロック内には変数aをとってテキストを保持しています。返り値として匿名関数を定義し、引数にbirthYearとして誕生年を渡します。この匿名関数のブロックではageという変数をとって、転換年での年齢を計算しています。console.log()を使って、JavaScriptコンソールに2019年時点での結果を表示する処理となっています。
これを次のようにして呼び出します。
var turningChina = turning(2025);
var turningSingularity = turning(2045);
var turningAging = turning(2040);
turningChina(1980);
turningSingularity(1980);
turningAging(1980);
turning(2050)(1980);
2025、2045、2040を引数にとって呼び出して、それぞれを変数に格納しています。この西暦の意味は順にチャイナ2025、シンギュラリティ、日本の高齢化問題と言われている年です。変数名もそれに合わせて定義しています。
これらの変数を括弧()で関数として呼び出して、引数に誕生年(ここでは1980年としています)を渡しています。
一番下では2050年問題をクロージャで一度に処理しています。左から順に処理して同様の処理をすることができます。
これらを実行すると、JavaScriptコンソールには次のように表示されます。
ここで、これに続けて、turningChina(1970); として呼び出してみます。
turningChina(1970);
このコードを先ほどのコードの下に続けて入力して実行してみます。
すると、JavaScriptコンソールにはこう表示されます。
一番下に結果が追加されていますが、ここでわかるのは、クロージャで返された匿名関数が引き続きローカル変数を保持しているということで、ここでは誕生年だけを変えただけで同様の処理ができていると言うのが確認できています。
関数を戻り値として返す関数をクロージャで書き換える
では、関数を戻り値として返す関数のところで使ったコードをクロージャを使って書き換えて見ようと思います。
コードを再掲すると次のようなコードになります。
function jobQuestion(job) {
if (job === '錬金術師') {
return function(name) {
console.log(name + '、 錬金術の「一は全、全は一」について教えてください。');
};
} else if (job === '機械鎧整備士') {
return function(name) {
console.log('ラッシュバレーの機械鎧はどうですか、' + name + '?');
};
} else {
return function(name) {
console.log('こんにちは、' + name + '。ご機嫌いかが?');
};
}
}
jobQuestion('錬金術師')('エルリック兄弟');
このコードをクロージャを使って書き換えるとどうなるか?
次のようになります。
function jobQuestion(job) {
return function(name) {
if (job === '錬金術師') {
console.log(name + '、 錬金術の「一は全、全は一」について教えてください。');
} else if (job === '機械鎧整備士') {
console.log('ラッシュバレーの機械鎧はどうですか、' + name + '?');
} else {
console.log('こんにちは、' + name + '。ご機嫌いかが?');
}
};
}
jobQuestion('錬金術師')('エルリック兄弟');
実行結果は同じになるはずです。
随分とコードがスッキリとなるのがわかると思います。
まとめ
ここではJavaScriptのクロージャを扱いました。
クロージャはローカル変数を参照している関数内関数ということになります。高階関数などの動きを復習しておくと良いでしょう。
クロージャで返された匿名関数が引き続きローカル変数を保持しているということで、匿名関数が有効である間は独立して利用することができます。