クロージャーとは
レキシカルスコープの変数を関数が使用している状態。
... えっ、なに?(汗
まず、レキシカルスコープとは
コードを書く場所によって参照できる変数が変わるスコープのこと。
うむ。{こういう状態とか}でスコープが変わることを言っているんだな。きっと。
個人的なクロージャーのイメージ
クロージャーじゃない状態 → { グローバル{関数A} }
クロージャーな状態 → { グローバル{関数B{関数A}} }
「この変数の値を簡単に触られたくない!」という場合、その変数を使う関数Aを関数Bで囲い、その変数を関数Bに置き、関数Aから関数Bの変数を参照できる状態にした上でグローバルからは触れないようにした状態!
勢いで言い切ってみましたが!
ちょっと違うかも...
ま、まぁとりあえず、上記のイメージを踏まえて実際のコードを見ていきたいと思います。自身でイメージを掴み、言語化できることが重要です。
呼ぶたびに変数numの値を1ずつ増やしていく処理をつくりたいが変数numは外から触られたくない → クロージャーを考える
下記の状態だと変数numは外部からアクセスできないものの、increment()を呼ぶ度に0で初期化されてしまう為、期待する結果を得られない...
function increment() {
let num = 0;
//ここでnumが常に0になる
num ++;
//そして+1される
console.log(num);
//当然logは1
}
increment();
increment();
increment();
increment();
//何度呼ぼうが... ↓
// log >>> 1
// log >>> 1
// log >>> 1
// log >>> 1
下記のようにすると期待する結果は得られるものの、変数numがグローバルにあるため触られ放題...
let num = 0;
function increment() {
num ++;
console.log(num);
}
increment();
increment();
increment();
increment();
// log >>> 1
// log >>> 2
// log >>> 3
// log >>> 4
上記2つの望みを叶えるものがクロージャー!
関数incrementを関数incrementFactoryで囲い、関数increment自体を関数incrementFactoryにreturnすることでグローバルから実行できるようしつつ、変数numの値はグローバルからは触られない!
//関数incrementの外側にその関数を覆うように関数を作成する
function incrementFactory() {
//ひとつ前の例でいうグローバル空間が今は関数に覆われていて非グローバル状態に
let num = 0;
function increment() {
//この関数内から「レキシカルスコープ」である変数numを参照しにいっている状態
num ++;
console.log(num);
}
//incrementFactoryに関数incrementを返すことでグローバルからincrementFactoryを通して実行できるようにする
return increment;
}
//ここの変数に関数incrementFactory内にある関数incrementが入る
//ここの変数名は何でも良い
const increment = incrementFactory();
increment();
increment();
increment();
increment();
// log >>> 1
// log >>> 2
// log >>> 3
// log >>> 4
なんとなく理解できたでしょうか?
わたしもなんとなく理解できた気がしますのでここにまとめてみました。
引き続き勉強していきます。
まとめ
クロージャーとは...
- ある関数の内側で定義されている関数が外側の関数が保持する変数(レキシカルスコープ)への参照を保持している状態!
- グローバルからひとつ中へ閉じられたスコープ空間を作るぜ!みたいな状態!