javaScriptのクロージャーでちょっと詰まった話
javaScriptの学習を進めていくと、一度クロージャの壁にぶち当たる。
クロージャーに入る前に、まずは変数のスコープについておさらいしてみる。
function test(val) {
return val;
}
console.log(test('テスト')) // テスト
console.log(val); // エラー Uncaught ReferenceError: val is not defined at...
上記コードのように、関数内で定義された変数 val を関数外で取得しようとしても、エラーになり、これにはスコープが影響している。
スコープにはいくつか種類があり、それぞれ参照範囲が異なる。
詳しくはこちらの記事を参考にしてほしい。
おねがい
上記の記事で満足してしまうかもしれないが、この記事に戻ってきてほしい
スコープの種類とクロージャーの概要について理解できたところで、ここからが本題。
私が詰まったところの説明をする。
const counterGenerator = (val) => {
let i = val;
return () => i += 1;
}
const test = counterGenerator(0);
test(); // 1
test(); // 2
test(); // 3
test(); // 4
上記コードを理解いただけただろうか。
関数test() を実行するたびに、返される値が変化(今回はカウントアップ)していくのである。
私は、初めこれにかなりの違和感を感じた。
同じく違和感を感じた初心者諸君、これから一緒にコード内容を紐解いていこう。
注意
ここからは誤った解釈があるかもしれない。先に謝っておく。
(コメントで教えて下さい)
まずはクロージャー部分
const counterGenerator = (val) => {
let i = val;
return () => i += 1;
}
関数 counterGenerator は、数値型の引数を一つとり、返り値として関数を返す。
この関数 counterGenerator に引数0を渡して呼び出し、返り値 test を変数に入れてみる。
const test = counterGenerator(0);
これで、変数 test には関数が代入された。
この test に、呼び出し演算子 () をつけて関数の呼び出しができる。
test(); // 1
test(); // 2
test(); // 3
test(); // 4
この部分だ。何度みても違和感しかない。
関数 test() を実行するたびに、関数内の変数 i がカウントアップされ、その値が返されてくる。
今回はそういう関数を、関数 counterGeneratorn 内で定義した。
この変数 i をプライベート変数といい、外部から直接操作したり、取得することができない。
その名の通りプライベートな変数だ。
test() だとぱっと見、なんの関数を実行しているのかわからないため、改めて定義する関数名を気をつけないといけないと感じた。
例えば、countUp() とか。
javaScriptの奥は深い。また詰まったことがあったら投稿する。以上。