クロージャとは何じゃ？

## はじめに
<details><summary>クロージャとは？</summary>

> クロージャは、組み合わされた（囲まれた）関数と、その周囲の状態（レキシカル環境）への参照の組み合わせです。言い換えれば、クロージャは内側の関数から外側の関数スコープへのアクセスを提供します。JavaScript では、関数が作成されるたびにクロージャが作成されます。

> クロージャは関数とその関数が作られた環境という 2 つのものの組み合わせです。この環境は、クロージャが作られた時点でスコープ内部にあったあらゆるローカル変数によって構成されています。

[クロージャ - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures)

</details>
:thinking::question:

## クロージャの前に
クロージャを理解するには、まずレキシカルスコープという概念を知る必要がある。クロージャは関数内で変数の参照を保持できる特徴があり、その挙動がレキシカルスコープに基づいて決まる。

## レキシカルスコープってどんなスコープ？

#### レキシカルスコープとは？
**関数が定義された場所でアクセスできる変数が決まるスコープ**のことで、
自分が所属する外側のスコープがレキシカルスコープになる。

#### レキシカルスコープの特徴
:::note
:writing_hand: **関数が定義された場所**で、どの変数にアクセスできるか決定
:::

:::note
:writing_hand: 内側の関数が所属するスコープの**外側のスコープ**がレキシカルスコープになる
:::
→実行中のコードから見た外側のスコープ

```javascript:レキシカルスコープの例 １
let global = 'グローバル変数';

function outerFunc() {
  let outer = '外側の関数の変数';

  function innerFunc() {
    let inner = '内側の関数の変数';
    console.log(global); // 'グローバル変数'
    console.log(outer); //  '外側の関数の変数'
    console.log(inner); // '内側の関数の変数'
  }
  innerFunc();
}
outerFunc();
```
* レキシカルスコープは、**関数が定義された場所で、どの変数にアクセスできるか決まる**
* 自分のスコープ内にない場合、外側のスコープ（親スコープ）へ探しに行く

`console.log(global)` : 
関数 innerFunc 内で global が見つからない → その外側の関数 outerFunc 内にもない → さらに外側のグローバルスコープを探す → 'グローバル変数'

`console.log(outer)` : 
関数 innerFunc 内で outer が見つからない → その外側のスコープ（outerFunc）にアクセス → '外側の関数の変数'

`console.log(inner)` :
関数 innerFunc 内で inner が見つかる → '内側の関数の変数'

```javascript:レキシカルスコープの例 2
let x = 10; 
function A(){
  console.log(x);  //この時の静的なスコープは x=10
}
function B(){
  let x = 1000;  //ここでもxが定義されている
  A();  //この時のxは 10? 1000?
}
A(); // 10
B(); // ?
```

レキシカルスコープは、**関数が定義された場所で参照する変数が決まる**。
→ 関数 B の内部で関数 A が呼ばれる時ではなく、関数が定義された時に決まっている。
関数 A の内部で x にアクセスすると、所属するスコープの外側のグローバル変数 x にアクセスする事になる。
```
B(); // 10
```
## クロージャの基本形
関数とその中にある変数、内部関数で構成され、内部関数が関数の戻り値となる。

```
関数 {
  変数
  return 内部関数
}
```

## クロージャの特徴

:::note
**変数のスコープの保持**
:::
<details><summary>「変数のスコープの保持」とは？</summary>

**外部関数のスコープ内で定義された変数へのアクセスを可能に。**<br/>→ 外部関数が実行を終了しても、クロージャ内で定義された変数は引き続き利用可能に。<br/>→ これにより、変数の値や状態を保持し、後続の関数呼び出しで再利用が可能になり、状態管理しやすくなる。
```javascript:例
function createCounter() { // 外部関数
    let count = 0; // 外部関数のスコープ内で定義された変数　内部関数からアクセス可能
    return function() { // 内部関数（クロージャ）
        count++; // スコープを保持し、countの値も保持
        return count;
    };
}

const counter = createCounter(); // 外部関数を実行、戻り値であるクロージャをcounterに格納
counter(); // クロージャを呼び出す
```

</details>

:::note
**プライベート変数としての機能**
:::

<details><summary>「プライベート変数としての機能」とは？</summary>

**クロージャ内で定義された変数は、外部からアクセスできない。**</br>
→ 変数の不要な変更/誤用を防止し、安全で整合性のあるコードの作成に役立つ。

```javascript:例
function createCounter() { // 外部関数
    let count = 0; // 外部関数のスコープ内で定義された変数　内部関数からアクセス可能
    return function() { // 内部関数（クロージャ）
        count++; // スコープを保持し、countの値も保持
        return count;
    };
}

const counter = createCounter(); // 外部関数を実行、戻り値であるクロージャをcounterに格納
counter(); // クロージャを呼び出す
// console.log(count)  外部からアクセスできない
// count = 10; としても代入不可、状態を保持
```
</details>

:::note info
**関数の再利用**
:::

<details><summary>「関数の再利用」とは？</summary>

**状態を持つ関数を生成することができる**</br>
→特定のデータを閉じ込めておくことで、同じ関数を異なる状態で再利用できる。</br>

* 「Don't Repeat Yourself」（繰り返さない）というDRY原則に従い、同じコードを繰り返さないようにすることができ、これによりエラーのリスクが減る。

```javascript:例
function createCounter() { // 外部関数
    let count = 0; // 外部関数のスコープ内で定義された変数　内部関数からアクセス可能
    return function() { // 内部関数（クロージャ）
        count++; // スコープを保持し、countの値も保持
        return count;
    };
}

const counter1 = createCounter(); // 最初のカウンター
const counter2 = createCounter(); // 別のカウンター　再利用

console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter2()); // ? 
console.log(counter2()); // ?
```
counter2の結果は、
```
console.log(counter2()); // 1
console.log(counter2()); // 2
```

それぞれが独立し別々の変数を参照している。
→ **各呼び出しで新しいスコープが作成され、各々は自分自身の状態を保持する。**

</details>

## 外側の関数を変数に代入する意味

```javascript:レキシカルスコープの例
function outerFn() {
    const outerVariable = 'outer scope';

    function innerFn() {
        console.log(outerVariable); //outerFn()によりinnerFnを返す
    }

    return innerFn;
}

const closure = outerFn(); // 代入して外側の関数のスコープを保持する
closure(); // 内側の関数を後で呼び出せる
```

:::note info
**const closure = outerFn();  ← 外側の関数を変数に代入する意味**
通常は、外側の関数 outerFn の中で定義された変数 outerVariable は、そのスコープ内でのみ有効

１）outerFn()によりinnerFnを返す
```
function outerFn() {
    const outerVariable = 'outer scope';

    function innerFn() {
        console.log(outerVariable); 
    }

    return innerFn; // innerFn を返す
}
```
２）変数 closureに代入して、 **外側のスコープを保持**
```
const closure = outerFn();
```
変数に代入する事で、**innerFnを保持** ＋ **outerFnのスコープも保持**

３）closure()を実行する
```
closure(); 
```
innerFnを呼び出す事になり、**クロージャーによって保持された参照**により外部からでもouterVariableにアクセスできる。
:::

:::note warn
**outerFn();** 
もし代入を行わなかった場合、
* 内側の関数 innerFnへの参照を失う（保持できない）
* その関数を"後で"呼び出せない

outerFn(); // クロージャが生成...　しかし、どこからも参照されない

「クロージャが生成される」とは、
* 内側の関数 innerFn が定義され、外側の関数 outerFn のスコープにある outerVariable を参照できる状態に
* このレキシカルスコープによって変数への参照がいったん保持される

しかし、外部からアクセスできない状態では、そのクロージャは無意味になる
↓ つまり、
**クロージャを有効活用にするには、どこかに参照を持たせることが必要**
:::

## レキシカルスコープは存在するが、クロージャではない
外側の関数（外側の関数によるスコープ）がない状態を例にする。
```javascript:例
let num = 0; // グローバル変数
function increment() { // 外側の関数が無い、numが外部からアクセス可能な状態
  num = num + 1;
  console.log(num);
}

increment(); // 1
increment(); // 2

num = 5; // numの値を外部から変更できてしまう
increment(); // 6（ここでは 変更された事によってnumが 5 からスタート）
```
レキシカルスコープは「**関数が定義された場所のスコープに基づいて変数にアクセスする**」
* increment 関数がグローバルスコープで定義されており、グローバルスコープ内の num にアクセスできる → **レキシカルスコープ**

* グローバルスコープにある num が外部からアクセス可能なため、後から関数を呼んでも、他の場所で num の値を変更することができてしまう　→ **クロージャではない**

:::note warn
状態のカプセル化がされておらず、予期しない動作を引き起こす可能性がある。
:::
→ **クロージャにすると、外部からの変更を防ぎ、安全に状態を管理することができる**。

## クロージャを使う時はガベージコレクションを意識する
:::note info
<font color="red">**ガベージコレクション**</font>
どこからも参照されなくなった変数を不要なデータと判断して自動的にメモリ上から削除する仕組みのこと
:::

クロージャの特徴に**変数のスコープの保持**がある。関数が生成された時点の環境を保持することで、外部関数の変数を長期間メモリに保持する可能性がある。

「関数の中で作成したデータは、その関数の実行が終了したら解放される」というわけではない。関数の中で作成したデータは、「関数の実行が終了した際に解放される場合」と「関数の実行が終了しても解放されない場合」がある。

:arrow_right: クロージャによって**メモリリーク**が発生し、ガベージコレクションに影響する。

::: note warn
<font color="red">**メモリリーク**</font>
メモリを確保した後、使い終わったメモリを解放せずに放置すると、不要なメモリが残り続ける現象。システム全体のパフォーマンスの低下の原因となる。
:::



```javascript:例）関数の実行が終了した際に解放される
function printX() {
    const x = "Hoge";
    console.log(x); // => "Hoge"
}
printX();
// "Hoge"を参照するものはなくなる -> 解放される
```
```javascript:例）関数の実行が終了した際に解放されない
function createArray() {
    const array = [1, 2, 3];
    return function() {
        console.log(array);  // 外部変数 `array` を参照
    };
}

const closure = createArray();  // 内部関数が返され、クロージャが作成される
closure();  // [1, 2, 3] という値を参照している -> 解放されない
```

* createArray()の返り値として closure に代入すると、closure がその array を保持し
createArray() の実行が終了しても**解放されない**

closure の参照を解放するには、
```
closure = null
```

```javascript:ガベージコレクションの対象となる例
function createArray() {
    const array = [1, 2, 3];
    return function() {
        console.log(array);  // 外部変数 `array` を参照
    };
}

const closure  = createArray(); 
closure();

closure  = null // 参照が解放される
```
closure = null とすることで、closure が参照していたクロージャも解放され、array もガーベジコレクションの対象となる。

## クロージャでグローバル変数を減らす
クロージャはグローバル変数を減らす有効な手段といえる。

:::note warn
**グローバル変数**：
アプリケーション全体でアクセス可能なため、予期しない副作用や名前の衝突が発生しやすくなる
:::

```javascript:クロージャを使用しない例
let counter = 0; // グローバル変数

function increment() {
  counter++;
  console.log(counter);
}

function decrement() {
  counter--;
  console.log(counter);
}

increment(); // 1
increment(); // 2
decrement(); // 1
```
クロージャを使うと、
```javascript:クロージャを使用する例
function createCounter() {
  let count = 0; // プライベート変数（グローバル変数を使っていない）

  return {
    increment: function() {
      count++;
      console.log(count);
    },
    decrement: function() {
      count--;
      console.log(count);
    }
  };
}

const counter = createCounter();

counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
```
この様に、クロージャを使用すると、データをプライベートに保ちながら、必要な部分にだけアクセスできるようにすることができる。(他のソースコードへの影響がない)

:::note info
クロージャは、<font color="red">**グローバル変数の使用を減らすために非常に有効な手段**</font>
:::

## クロージャと高階関数　結果は同じだが...
高階関数が必ずクロージャを生成するわけではないが、高階関数の一部の使い方にはクロージャの性質が関係していることがあり、クロージャを作るケースがある。

まず、普通の関数と高階関数の違いは、
* 普通の関数 → 単に引数を受け取って結果を返す
* 高階関数 → 関数を引数として受け取ったり、返り値として関数を返したりする

```javascript:普通の関数の例
function add(a, b) {
  return a + b;
}

console.log(add(1, 2));  // 3
```


```javascript:高階関数だがクロージャではない例
function add() {
  return function(x) { // 高階関数の特徴
    return x + 1;
  };
}

const increment = add(); // add を呼び出すと、関数が返される
console.log(increment(2));  // 3　
```
この例では、"外部の変数を参照しない"関数が返されるため、クロージャは発生しない。

**クロージャが発生する条件：
返される関数が外部スコープの変数を参照している必要がある**

これを、高階関数でクロージャにするには、

```javascript:高階関数でクロージャの例
function add(num) {
  return function(x) { //　クロージャ
    return x + num; //　num（外部スコープの変数）にアクセス
  };
}

const increment = add(1);
console.log(increment(2));  // 3　
```
返された関数は、外部の変数 num を「記憶」しており、num にアクセスできるため、クロージャといえる。

ここで、高階関数でクロージャだが、外側の関数が引数を持つか持たないかを比べてみる。

```javascript:高階関数でクロージャ / 外側の関数に引数がない例
function multiplier() {
    let num = 2;  // num を内部で固定
    return function(x) {
        return x * num;
    };
}

const double = multiplier();
console.log(double(5));  // 10
```
numは内部で 2 に固定されおり、返された関数は、常に2倍の計算しかできない。

:::note warn 
高階関数でクロージャだが、
num を固定しているため、**高階関数の"柔軟性"や"再利用性"が活かされていない**
:::
num の値を動的に設定できるようにしたい場合、外側の関数に引数を与えると、numを外部から指定できる様になる。
```javascript:高階関数でクロージャ / 外側の関数に引数がある例
function multiplier(num) {
    return function(x) {
        return x * num;
    };
}

const double = multiplier(2);  // 2で掛け算する関数を作る
console.log(double(5));  // 10
```

```javascript
const triple = multiplier(3);  // 3で掛け算する関数を作る
console.log(triple(5));  // 15
```
:::note info
外側の関数に引数として受け取るようにすることで、
* 動的な関数として、高階関数の本来の特徴である**再利用性**が高まる
* 引数に意味を持たせる事で、**可読性**も高まる
:::

## 参考
[クロージャ - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures)
>クロージャは、組み合わされた（囲まれた）関数と、その周囲の状態（レキシカル環境）への参照の組み合わせです。言い換えれば、クロージャは内側の関数から外側の関数スコープへのアクセスを提供します。JavaScript では、関数が作成されるたびにクロージャが作成されます。

>クロージャは関数とその関数が作られた環境という 2 つのものの組み合わせです。この環境は、クロージャが作られた時点でスコープ内部にあったあらゆるローカル変数によって構成されています。

[【JavaScript】クロージャについて解説](https://zenn.dev/ryu0947/articles/109e6dd29bf7f2)
>クロージャとは、関数内で使用されている変数がレキシカルスコープの変数の値を保持し続けている状態

[【JavaScript】スコープとクロージャ](https://qiita.com/Yu-8chan/items/35e774cee33e10e819d7)
>クロージャとは、レキシカルスコープの変数を関数が使用している状態のこと

[変数スコープ、クロージャ](https://ja.javascript.info/closure)
>クロージャ(closure) は外部変数を記憶し、それらにアクセスできる関数

[JavaScriptの即時関数とクロージャについて現役エンジニアが解説【初心者向け】 | TechAcademyマガジン](https://magazine.techacademy.jp/magazine/37155)
>クロージャとは内部関数が戻り値になる構造のことです。

[JavaScript - クロージャと引数の関係を理解しよう【完全ガイド】｜Kevi Log (ケビろぐ！)](
https://yminamiyama.com/javascript-closure-arguments-guide/)
>クロージャとは、関数が他の関数内で定義され、その外部関数の変数にアクセスできる機能です。

[【JavaScript】クロージャー（Closure）について](https://yuito-blog.com/closure/)
>クロージャとは「レキシカルスコープにある変数や引数への参照を保持し続ける」という関数が持つ性質のことです。

[関数とスコープ · JavaScript Primer #jsprimer](https://jsprimer.net/basic/function-scope/)
>クロージャーとは「外側のスコープにある変数への参照を保持できる」という関数が持つ性質のことです。

[【JavaScriptの基礎】レキシカルスコープとクロージャを理解する | WEMO](https://wemo.tech/904)
>クロージャは「関数」と「その関数が作られた環境」という 2 つのものが一体となった特殊なオブジェクト