クロージャとは

※[クロージャと変数のスコープ(追記)](#クロージャと変数のスコープ追記)を追記しました。

※コメント欄で**環境**という用語について議論がありましたが、そもそも**環境**は専門用語として存在します。詳しくは[環境を持つというイメージ](#環境を持つというイメージ)に追記しました。

使い古された話題ではありますけど、わかりやすく説明できそうな気がしたので書いてみたいと思います。

先に方針だけ伝えておくと、**クラス**と**モジュール**と**関数**は、**変数のスコープを切ることができる**という共通の性質を持っている、という切り口からクロージャについて説明していきたいと思います。

これだけ読んで何となく先が予想できてしまった人は読まなくても大丈夫かと思います。

それでも読んでくださるという方は、助言なり意見なりをくださるととても嬉しいです。

# 実行環境

言語はJavaScript(ES2015 or later)を使いますけど、別に知らなくてもなんとかなるんじゃないでしょうか。
何か他の言語をやっていれば大体読めるかと思います。

実行環境はNode.js(v6.9.0 or later)です。
なのでモジュールはCommonJSでやります。

まあわからない人は全然気にしなくても大丈夫です。

以下で出てくるコードを実際に動かしてみたいという人は、[公式サイト](https://nodejs.org/en/download/)からインストーラを落としてくるなりパッケージマネージャ使うなりしてNode.jsをインストールすれば問題はないかと思います。

# 関数が第一級オブジェクト(ファーストクラスオブジェクト)とは

~~クロージャは関数が第一級オブジェクトである言語でしか使えませんので、先に第一級オブジェクトについて説明します。~~

**クロージャは関数が第一級オブジェクトでない言語でも存在します**。

勉強不足な僕の勝手な思い込みで**クロージャは関数で作るもの**と思っていたんですけど、そうでもないようです。

関数はないけどクロージャはある例としてRubyなどが挙げられるみたいですね。

詳しくはコメント欄を見ていただければと思いますけど、指摘していただいた @raccy さんに感謝です。

ただ関数でクロージャを表現している言語は多いと思いますので、以下の内容は知っておいた方がいいとは思います。

知っているという人は[環境を持つというイメージ](#環境を持つというイメージ)に進んでもらえればと思います。

第一級オブジェクトとは、その言語で**値として扱えるデータのこと**です。

オブジェクトとは言いますけど、オブジェクト指向のオブジェクトとはまた別の意味を持ちます。

まあ「対象物」とか「値」くらいのふわっとした意味でとらえていただければ大丈夫かと思います。

脱線しましたが、**値として扱える**というのは、**代入できたり関数の引数にできたり、戻り値にできたりする**という意味です。

~~例えばCやPHPでは、関数は第一級オブジェクトではありません。~~

Cでは関数は第一級オブジェクトではないようですが、PHPには無名関数があるため関数が第一級オブジェクトとなっているようでした。

話を戻しまして、Cは関数自体を関数の引数や戻り値にできません。

しかし、PythonやJavaScriptでは関数を変数に代入したり、関数に渡したりすることができます。

代入したり引数にしたりできるということは、当然関数を値として生成する方法もあります。

以下はJavaScriptのコードです。

```javascript:functions.js
// 関数(のインスタンス)を生成し、変数に代入
const add1 = function(a) {
  return a + 1
}

console.log(add1(3)) // => 4

// 関数を引数に取る
function apply(a, f) {
  return f(a)
}

console.log(apply(2, add1)) // => 3
```

`node functions.js`で実行できます。

あと`// => 4`には深い意味はなく、ただ実行結果のスクリーンショットを取るのが面倒だったので、実行したときに表示される結果をコメントに書いただけです。

`console.log`は`print`みたいな標準出力に表示する関数ですね。

また、JavaScriptでは`function foo(a) {...}`と`const foo = function(a) {...}`がほぼ同じ意味になります。

```javascript
// 以下の2つはほぼ同じ意味
function div(a, b) {
  return a / b
}

const div = function(a, b) {
  return a / b
}
```

関数が第一級オブジェクトであるJavaScriptでは、**fooという名前の関数を定義する**ことと**関数をfooという名前の変数に代入する**ことは同じようなことなんですね。

※厳密には違ったりするので「JavaScriptでは」「同じような」と誤魔化してますけど許してください

あとなんとなくわかるとは思いますけど、上のコードを1つのファイルに書いて実行してしまうと「`div`はすでに宣言されてる」って怒られますからね。

気を取り直しまして。

**関数が第一級オブジェクトである**ということのイメージは、なんとなくつかんでいただけたのではないでしょうか。

関数を変数に代入してみたり、引数として渡してみたり、関数の返り値にしてみたりといったことにはなれるまで時間がかかるかもしれませんけど。

# 環境を持つというイメージ

クロージャは英語ではClosure、日本語では関数閉包ですね。

イメージは**自身が定義されたときの環境を持った関数**[^1]です。

[^1]: これはクロージャによって補足された変数が**静的スコープで解決される**ということでもあります。

~~環境とは、変数などの状態のことでもありますね。~~

環境とは、**名前(変数名)と値のペアのリスト**です。

```
[(x, 2), (y, 4), (z, 8)]
```

大体こんな感じのものです。

この**関数が環境を持つ**っていうのがなかなか想像がつかないポイントだと思うんですよ。

でもこれ、実は結構簡単なお話で、例えばオブジェクト指向の言語(JavaやPHPやC#など)のクラスは、**フィールドやプロパティと呼ばれる~~内部状態(変数)~~変数**を持っていますよね。

クラスではこの**プロパティの名前と値のリスト**が環境に相当します。

またクラスがない言語でも、モジュールが変数を持つことができたりします。

モジュールでは、**内部で宣言された変数の名前と値のリスト**が環境になりますね。

つまり、**クラスやモジュールは環境を持っている**のです。

それと同じで、**関数も環境を持つことができる**のです。

そして**環境を持った関数**のことを**クロージャ**と呼びます。

ただ、関数が環境を持つというのは少しイメージがしづらいのではないでしょうか。

なので、実際にコードを見ていきたいと思います。

これもまた使い古された例なんですけど、数を数えるカウンターを題材にしてみたいと思います。

# クラス(のインスタンス)が持つ環境

```javascript
class Counter {
  constructor() {
    this.countNumber = 0
  }

  count() {
    this.countNumber += 1
    return this.countNumber
  }
}

const counter = new Counter()

console.log(counter.count()) // => 1

console.log(counter.count()) // => 2

console.log(counter.count()) // => 3
```

`// => 1`は、実行したときに表示される値をコメントとして書いているだけです。

また、JavaScriptではクラスのフィールドを宣言する方法がありませんので、コンストラクタの中でいきなり代入します。

それにだけ気を付ければ、オブジェクト指向をやったことがある人はたぶん簡単に読めますよね。

やったことのない人も、なんとなく意味はつかめるかと思います。
ちなみに`constructor`は`new`したときに実行される関数で、`this`はそのクラス(のインスタンス)自身を指します。

インスタンスは`new`でクラスから実際に生成され変数に代入される値のことですね。

どちらにせよ、**クラス(のインスタンス)が持つ環境**の意味はつかんでいただけたのではないでしょうか。

簡単にだけ説明しておきますと、クラスの外部に公開されたメソッド`count`から、クラス内部の環境であるフィールド`counterNumber`を変更することができています。

# モジュールが持つ環境

```javascript:counter.js
let countNumber = 0

function count() {
  countNumber += 1
  return countNumber
}

module.exports = {
  count: count
}
```

```javascript:main.js
const counter = require('./counter.js')

console.log(counter.count()) // => 1

console.log(counter.count()) // => 2

console.log(counter.count()) // => 3
```

モジュールと言うと言語ごとに多少意味が異なってきますけど、ここでは**関数や変数、クラスなどをまとめたもの**くらいのふわっとした理解で大丈夫かと思います。

`module.exports`とか`require`とかはCommonJSというモジュールシステムのお作法です。

あと、CommonJSではモジュールとファイルが深く結びついているので、上のコードだけはそれぞれ別のファイルに書いて実行する必要があります。

何をしているのかなんとなくはわかるのではないでしょうか。

先ほどのクラスがモジュールになっただけのような気がしますね。

モジュール内で宣言された変数が、**モジュールが持つ環境**となります。

これも一応説明しておきますと、モジュールの外部に公開された関数`count`から、モジュール内部の環境である変数`counterNumber`を変更することができています。

[クラス(のインスタンス)が持つ環境](#クラスのインスタンスが持つ環境)と**ほとんど同じことを言っています**よね。

# 関数が持つ環境(クロージャ)

いよいよクロージャです。

クロージャとは**環境を持った関数**です。

ここで少し、[クラス(のインスタンス)が持つ環境](#クラスのインスタンスが持つ環境)と[モジュールが持つ環境](#モジュールが持つ環境)を振り返ってみたいと思います。

どちらも、**関数(メソッド)`count`と変数`counterNumber`がセットなっています**よね。

そして、それら2つをまとめているものは**クラス(のインスタンス)が持つ環境**では**クラス(実際にはそのインスタンス)**であり、**モジュールが持つ環境**では**モジュール**となっています。

ということはですよ。

**関数が持つ環境**では、**関数`count`と変数`countNumber`のセットが関数によってまとめられる**と予想できるのではないでしょうか。

なので、そこらへんを意識しながら以下のコードを読んでみてくださいね。

```javascript:closure.js
function createCounter() {
  let countNumber = 0

  const count = function() {
    countNumber += 1
    return countNumber
  }

  return count
}

const counter = createCounter()

console.log(counter()) // => 1

console.log(counter()) // => 2

console.log(counter()) // => 3
```

どうでしょう、何となく読めたのではないでしょうか。

ただ**関数を返す関数**というのは、なじみのない人にはわかりにくいかもしれませんね。

それは少しおいておくとして。

これも同じく説明してみますと、関数が外部に公開した関数、つまり返り値にした関数`count`から、関数内部の環境である変数`counterNumber`を変更することができています。

少し変則的なのは、**クラス**と**モジュール**ではそれぞれ**環境を持つのはクラス(のインスタンス)/モジュールで、それを変更するのは外部に公開した関数(メソッド)`count`**であったのに対し、**関数**では**環境を持っているのは関数自身であり、環境を変更するのもまたその関数自身である**、というところですね。

         | 環境を持っているもの      | 環境を変更するもの
 ------- | ---------------------- | ---------------
クラス    | クラス(のインスタンス)自身 | メソッド
モジュール | モジュール自身           | 公開した関数
クロージャ | クロージャ自身           | クロージャ自身

まあでも、大体似たような説明ができましたよね。

さらに、今まで出てきた**クラス**と**モジュール**、そして**関数**にはある共通点があります。

それは、**変数のスコープを切ることができる**という点です。

それらを利用して**内部に環境(変数)を持たせ**、さらに**外部に公開した関数から内部の環境(変数)にアクセスする**ことができるんですね。

そう考えると、クラスもモジュールも関数も似たようなもので、クロージャは至極当たり前のものなんじゃないかな、とちょっと思えないでしょうか。

そう思っていただけたのなら、今回の僕の目論見は成功したことになりますね。

# クロージャと変数のスコープ(追記)

もう一度[関数が持つ環境(クロージャ)](#関数が持つ環境クロージャ)のclosure.jsのコードを見てほしいんですけど、変数`count`に代入されている関数(この関数はクロージャ)がありますよね。

その関数の中で使用されている変数`countNumber`は、この関数の中だけ見れば存在しないはずの変数です。

このような、関数の中だけ見たときに**引数にもないし宣言もされていないのに突然現れる変数**を**自由変数**と言います。

closure.jsのコードを読んでいたときは、その関数(クロージャ)の外で変数`countNumber`が宣言されているのでそれを使っているのかなとなんとなく思っていただけていたのではないでしょうか。

こういう**関数の自由変数が、その関数の定義時の環境で解決される**ことを**クロージャが変数を捕捉する**という言い方をします。

なんとなく、関数がその外の変数を持ってきて、自分のものにしているように見えますよね。

```javascript
function createCounter() {
  let countNumber = 0

  const count = function() {
    countNumber += 1
    return countNumber
  }

  return count
}
```

そう考えてみると、「捕捉する」という言い方にも納得できそうな気がします。

この**変数を捕捉する**という言い回しはクロージャの絡む話ではたびたび見かけますので、ぜひ覚えておいた方がいいかと思います。

というわけで、JavaScriptでは関数内の自由変数は**その関数定義時の環境で解決される**ので変数の捕捉が起こっていたわけなんですけど、実はそうではない言語もあるんですよ。

以下はJavaScriptっぽく書いていますが、ある仮想言語のコードです。

```javascript
function addx(y) {
  return y + x
}

let x = 3

let z = addx(4)

z // => 7
```

先ほどまでのJavaScriptのコードとはかなり違った動きをしているように見えます。

JavaScriptでは、関数内の自由変数は**その関数の定義時の環境で解決される**んでしたよね。

でもこの仮想言語では、関数内の自由変数は**その関数の実行時の環境で解決されている**んですよ。

少しイメージしづらいかもしれませんけど、**関数は呼び出された場所にそのまま展開される**と考えれば思ったより簡単に理解できるかと思います。

```javascript
function addx(y) {
  return y + x
}

let x = 3

let z = x + 4

z // => 7
```

これなら読めますよね。

でもこれ、変数の名前解決の方法としては、不思議なというか、なんだか少し危なそうな感じがしませんか(これは僕の偏見です)。

それは置いておくとして。

JavaScriptのように関数内の自由変数が**その関数の定義時の環境で解決される**変数スコープのことを**静的スコープ**と言います。

同じように、上の仮想言語のように関数内の自由変数が**その関数の実行時の環境で解決される**変数スコープのことを**動的スコープ**と言います。

動的スコープと静的スコープ、聞いたことはあるという人が多いのではないでしょうか。
**自由変数をどう解決するか**という違いだったんですね。

またクロージャでは、自由変数が静的スコープで解決される必要があります。

なぜでしょうか。

それはJavaScriptでクロージャを書いたコードを、先程の**動的スコープを持つ仮想言語**で書いてみた場合の実行結果を見ればわかるのではないかと思います。

```javascript:closure.notjs
function createCounter() {
  let countNumber = 0

  const count = function() {
    countNumber += 1
    return countNumber
  }

  return count
}

const counter = createCounter()

let countNumber = 10

const result1 = counter()
console.log(result1) // => 11

const result2 = counter()
console.log(result2) // => 12

countNumber = 0

const result3 = counter()
console.log(result3) // => 1
```

どうでしょう、読めましたでしょうか。

全然クロージャしていませんよね(これは勝手な造語です)。

関数`createCounter`内の変数宣言`let countNumber = 0`が見事に無視されています。

これは**自由変数が動的スコープで解決される**ため、**定義時の環境は関係ない**からです。

同じ理由で、`let counterNumber = 10`を書かないと、関数`counter`の実行時に「変数`countNumber`がないよ」と怒られてしまいます。

**関数`counter`の実行時の環境に変数`countNumber`が宣言されている必要がある**からですね。

上のコードだけではわかりにくいという人は、先ほどの**関数が呼び出された場所にそのまま展開される**というイメージを利用すると読めるようになるかと思います。

```javascript:closure.notjs
function createCounter() {
  let countNumber = 0

  const count = function() {
    countNumber += 1
    return countNumber
  }

  return count
}

const counter = createCounter()

let countNumber = 10

const result1 = {
  countNumber += 1
  return countNumber
}
console.log(result1) // => 11

const result2 = {
  countNumber += 1
  return countNumber
}
console.log(result2) // => 12

countNumber = 0

const result3 = {
  countNumber += 1
  return countNumber
}
console.log(result3) // => 1
```

少し特殊な書き方をしていますけど、大体意味はわかりますよね。

関数`createCounter`は、定義時に変数`countNumber`を捕捉しない関数`count`を返します。

そして変数`counter`に代入された関数`count`の実行時の環境で、その中の変数`countNumber`が解決されるんですね。

これで動的スコープではクロージャが成り立たないことがわかっていただけたかと思います。

以上、クロージャと変数スコープについての追記でした。

# よく紹介されるクロージャの不思議挙動

```javascript
function createCounter() {
  let countNumber = 0

  const count = function() {
    countNumber += 1
    return countNumber
  }

  return count
}

const counter1 = createCounter()
const counter2 = createCounter()

console.log(counter1()) // => 1

console.log(counter2()) // => 1

console.log(counter1()) // => 2

console.log(counter2()) // => 2
```

「あれ、表示される数が増えてないところがある！」

ここまで読んでくださった方は、たぶんですけどそんなこと思いませんよね。

イメージがつかめていれば、そんなに難しいことではなく、当たり前の挙動に見えますよね。

わからないという人は、クラスの場合を考えてみてください。

```javascript
class Counter {
  constructor() {
    this.countNumber = 0
  }

  count() {
    this.countNumber += 1
    return this.countNumber
  }
}

const counter1 = new Counter()
const counter2 = new Counter()

console.log(counter1.count()) // => 1

console.log(counter2.count()) // => 1

console.log(counter1.count()) // => 2

console.log(counter2.count()) // => 2
```

オブジェクト指向をやっている人には当たり前すぎることですよね。

でもですね、ここで「あれ、モジュールは？」と疑問に思う方がいるかもしれません。

それか、もっと前から「これはおかしい」って怒り心頭だった人もいるかもしれませんね。

そうです、**モジュールでは上のような挙動はできない**のです。

オブジェクト指向をちゃんと理解している人向けに言うと、**モジュールにはクラスにおけるインスタンス相当のものがない**のです。
あってもシングルトンになっているのではないかと思います。

モジュールの例のカウンタは、`require`したすべてのファイルで共通のカウンタ変数を使ってしまうことになります。

ですので、モジュールは厳密に言うと今回の説明に出すべきではありませんでした。

でも、クラスだけだとクロージャのイメージをつかみにくいかなあという苦渋の決断の元、イメージだからいいやという免罪符を手にモジュールも出すことにしました。

一応理由を説明したので許していただけるとありがたいです……

# まとめ

**クラス**と**モジュール**と**関数**が、**変数のスコープを切ることができる**という似たような性質を持っている、という切り口からクロージャについて説明してみました。

クロージャのイメージをなんとなくでもつかんでいただけたのでしたら幸いです。

クロージャを理解していながらも読んでくださった方は、助言や意見をいただけるとなおのことありがたいです。

「これちゃんと理解して書いてるのかな」とか、「ここは意味を取りづらいんじゃないか」とか、「この表現は正確ではない」とか。

あんまり厳しい言い方だと心が折れそうなので、できれば優しく教えていただきたいですけど。