JavaScriptのクロージャについて

# 初めに
何かわかるけど実際分かっていない`Closure`、今回も自分なりに自分の理解をまとめていきたいと思います。
主な参考資料はこちらです↓
[You Don't Know JS: Scope & Closures - 1st Edition](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20&%20closures/README.md#you-dont-know-js-scope--closures)

そして[TL;DRの方へ](https://qiita.com/drafts/4e1c6253c85d1093e1d4/edit#tldr)

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

少し調べたら、思ったよりJavaScriptエンジンにある深層部の知識がたくさん関連していることが分かって、`Scope`と`Lexing scope`の概念も一緒にまとめたいと思います。


# `Scope` and `Lexing Scope`
主な参考資料はこちらです↓
[Chapter 1: What is Scope?](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch1.md)
[Chapter 2: Lexical Scope](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch2.md)
[Chapter 5: Scope Closure](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch5.md)

##  `Scope`
自分の理解で要約してみると、`Scope`というのは変数の貯蔵庫であり生存領域として、コードを実行する前に、`Compiler`（JavaScriptならJavaScriptエンジン）が`compilation`を行う場所です。

そして`compilation`は三つのステップで構築されている。
- Tokenizing/Lexing：ソースコードの文字列を解析してトークンを得る。
`var a = 2;` ⇒ `var`, `a`, `=`, `2`, `;`
- Parsing：トークンで抽象した木構造のツリー（Abstract Syntax Tree, AST）へ構築していく。
`var`：VariableDeclaration（変数宣言）
`a`：Identifier（識別子）
`=`：AssignmentExpression（代入式）
`2`：NumericLiteral（数字リテラル）
```
　　var
　/　　 \
a        =
         |
         2
```

- Code-Generation：この段階では上のASTを執行可能の機械言語に変換する。
結果としては、`var`で変数宣言し、`a`という変数に、数字`2`を入れて保存する。

さらにプログラムを実行する一連の処理はエンジン、コンパイラ、スコープが互いに支えあって各自の役割を果たしている。
- Engine：初めの`compilation`から最後の`execution`まで、プログラムを実行する任務を任される。
- Compiler：`compilation`の三つのステップを経てコードを処理する。
- Scope：宣言された識別子（変数の`a`とか）のリストをしっかりと確立し管理する。

さきほど`var a = 2;`の例では、コード実行すると、
まず`Compiler`が`Scope`に、`a`という変数がすでにある特定のスコープに生存しているかと問いかけ、もし答えがYesなら`a`の変数宣言を無視して次に進む。もし答えがNoなら`a`という新しい変数を設ける。
そして次`a = 2`代入式の部分では、`Engine`は`Scope`に、このスコープで`a`という変数がアクセスできるかと聞き、Yesなら`Engine`は変数を利用する。Noなら、`Engine`はほかのネストしたスコープ（自分より上のスコープ）をチェックしていく。
変数見つかったら`2`を与える。どこでも見つからなかったら、`Engine`はエラーと示してくる。
```jsx: nested Scope example
function outerFn() {
  var a = 1
  function innerFn() {
    var b = 2
    console.log('a:', a, 'b:', b, 'a+b:', a + b)
  }
  innerFn()
}

outerFn() // a: 1 b: 2 a+b: 3
```

##  `Lexing Scope`
ほかのプログラミング言語では`Scope`を静的スコープ`Lexing Scope`と動的スコープ`Dynamic Scope`に分けられ、しかしJavaScriptは`Lexing Scope`しか持っていません。
`Lexing Scope`は`var a = 2;`のような文字列を解析しトークンを得る`compilation`の第一ステップです。
そしてどこのスコープで`compilation`を実行するかはコードを書くときすでに決定されている。
```jsx: example1
function outerFn(a) {
  const b = a * 2
  function innerFn(c) {
    console.log('innerFn a:', a) // innerFn a: 5
    console.log('innerFn b:', b) // innerFn b: 10
    console.log('innerFn c:', c) // innerFn c: 30
  }
  innerFn(b * 3)
  console.log('outerFn a:', a) // outerFn a: 5
  console.log('outerFn b:', b) // outerFn b: 10
  console.log('outerFn c:', c) // ReferenceError: c is not defined
}

outerFn(5)
// innerFn a: 5
// innerFn b: 10
// innerFn c: 30
// outerFn a: 5
// outerFn b: 10
// ReferenceError: c is not defined
```
`global scope`に識別子がただ一つ`outerFn`で、
`outerFn scope`に`a`, `b`, `innerFn`識別子、
`innerFn scope`に`c`識別子があります。
ネストしたスコープは自分より外／上のスコープ（outward/upward）へ変数や値などアクセスできるが、自分より下のスコープへアクセスできない特性を持っているので、`outerFn`で`c`を出力することが不可能です。

そしてスコープ範囲内で識別子を探すのは`shadowing`と呼ばれて、同じ変数が別々のスコープに存在しても、識別子にたどり着いたらすぐストップする。
```jsx: example2
function outerFn(a) {
  const b = a * 2
  console.log('outerFn a:', a) // innerFn a: 3
  console.log('outerFn b:', b) // innerFn b: 6
  function innerFn(c) {
    const b = a * 10
    console.log('innerFn a:', a) // innerFn a: 3
    console.log('innerFn b:', b) // innerFn b: 30
  }
  innerFn(b * 3)
}

outerFn(3)
```
## 結局、`Closure`って何？
`example1`のように、`innerFn`で変数`a`の値を出力するから、`outerFn`の変数`a`へアクセスし、RHSを通して値をゲットするのが`Closure`？
確かに私もそう理解してきていますが、参考文章によるとこれは不完全な解釈のようだった。
私たちがみた内部関数が外部変数の値への要請は、正確に言えば`lexical scope`のlook-upルールを通して`Closure`になった一部の結果にすぎません。

```jsx
function outerFn() {
  const a = 1
  return function innerFn() {
    console.log('innerFn a:', a)
  }
}

const test = outerFn() // outerFn() returns innerFn
test()
```
変数`test`に`outerFn()`を入れたのは、`outerFn`関数ではなく`outerFn()`関数の実行した結果、つまり`innerFn`関数です。
そして`innerFn`関数は変数`a`を出力ということで、`lexical scope`のlook-upルールを通して、`outerFn`関数の変数`a`へたどり着くんです。
`Engine`はメモリー回収という機能を持ち、不要なものをクリーニングするのですが、`innerFn`関数が値として変数testへ入れる状態では、`innerFn`自身も、変数`a`が生存している`outerFn`からメモリー回収が不可能なので、`Closure`状態になっている。

# TL;DR
簡潔に言うと、`return`の値は関数でそして外部の変数を使っているなら`Closure`状態になります。

# おまけ
いろいろ試行錯誤の中書いてみたコード例です。
例を参考した文章はこちらです↓
[Closures and currying](https://fbuireu.medium.com/closures-and-currying-9774676d33fa#:~:text=Currying%20means%20that%20the%20closure,other%20arguments%20as%20you%20go.)
```jsx
const closureFunction = someVariable => {
  let scopedVariable = someVariable

  const closure = () => {
    scopedVariable++
    console.log(scopedVariable)
  }

  return closure
}

let testOne = closureFunction(1)
testOne() // 2
testOne() // 3

let testTwo = closureFunction(10)
testTwo() // 11
testTwo() // 12

testOne() // 4


// the same
let scopedVariable = 0

const closureTest = function closure() {
  scopedVariable++
  console.log(scopedVariable)
}

closureTest() // 2
closureTest() // 3

scopedVariable = 10
closureTest() // 11
closureTest() // 12
```