[javascript]はじめてのクロージャ



jsのクロージャについて、勉強したのでまとめてみる。入門者向け。

2015/09/02


##キーワード

<!-- - クロージャ -->
<!-- - 隠蔽 -->
- スコープ
- 関数の中の関数
- 状態を保持する関数


##クロージャとは？

わからないことがあったら、まずはWikipediaですよね。

<blockquote>
関数閉包はプログラミング言語における関数オブジェクトの一種。引数以外の変数を実行時の環境ではなく、自身が定義された環境（静的スコープ）において解決することを特徴とする。
...wikipediaより
</blockquote>


？？？

何を言ってるのか、よくわからないですね。

気を取り直して、はてなキーワードを見てみます。

<blockquote>
閉包。関数内に出現する自由変数（関数内で宣言されていない変数）の解決の際、実行時の環境ではなく、関数を定義した環境の変数を参照できるようなデータ構造。
...Hatena Keywordより
</blockquote>


・・・

わからない・・・


##つくってみよう

よくわからないので、とりあえず作ってみましょう。


数字をカウントアップする関数を作ってみます。

```javascript
var num = 0;
function countup(){
    return ++num;
}

// できた。動かしてみます。

console.log( countup() );  // => 1
console.log( countup() );  // => 2 うんいい感じ。

num = 0;  // ←

console.log( countup() );  // => 1 あれれ。
```

カウントアップする関数なのに、途中で0に戻ってしまいました。
これではまずい。



##スコープを切ろう

変数の<b>スコープ</b>を切って、上書きされないようにしましょう。

```javascript
// var num = 0;
function countup(){
    var num = 0;  // ← 移動
    return ++num;
}

// 動かしてみよう。

console.log( countup() );  // => 1
console.log( countup() );  // => 1 カウントアップしてない。
num = 0;  // ←
console.log( countup() );  // => 1 スコープは切れてるけど。
```

できない。（そりゃそうだ）

スコープは切れてるけど、状態が保持されていない。
（毎回初期化されている）


##そこでクロージャ。

そこでクロージャですよ。

```javascript
var countup = (function(){
    var num = 0;
    return function(){
        return ++num;
    };
})();

// 実行すると、

console.log( countup() );  // => 1
console.log( countup() );  // => 2 いいね
num = 0;  // ←
console.log( countup() );  // => 3 おっ できてる。
```

できた。

ちゃんとカウントアップもされてて、スコープも切れていますね。

最初のコードと2番目のコードをくっつけた感じ？


##軽く解説
軽くコードの解説をすると、

```javascript
var countup = (function(){
    ...
})();
```
全体としては、即時関数を実行しその返り値を変数countupに代入しています。

<!-- （必ずしも即時関数である必要はないです） -->

変数numはこの外側の関数(即時関数)の中で宣言されています。
<br>
そしてその即時関数の返り値が、

```javascript
return function(){
    return ++num;
}
```
関数になっている！

関数の中に関数がありますね。

変数countupには、この内側の関数が代入されることになります。

変数numはこの内側の関数の外で宣言されていますね。

<!--
function countup(){}
var countup = function(){};
はここではほぼ同義と考えます。


まさに、最初のコードと2番目のコードをくっつけた感じですね。
-->


##つまり、クロージャとは

<!-- 最初のコードを、functionでラップしてる感じ？
関数で包んで、スコープを切ることで、変数を隠蔽して、安全性を保っています。
クロージャの中のnum変数には何人たりともアクセスできません。 -->


このように、
(外側の)関数の中にnumが宣言されていることで、スコープが切れていて、
(内側の)関数の外にnumが宣言されていることで、状態が保持されている。

これこそがクロージャなのです！

```javascript
var countup = (function(){
    var num = 0;
    return function(){  // 関数の中に関数がある
        return ++num;
    }
})();

console.log( countup() );  // => 1
console.log( countup() );  // => 2  ちゃんとカウントアップされてる（状態が保持されてる）

num = 0; // 上書きしようとしても
console.log( countup() );  // => 3  できない（スコープ切れてる）
```

<!--
・スコープが切れてて
・関数の中に関数があって
・状態を保持できる構造
-->


<!-- ##まとめ -->

##キーワードをもう一度

- スコープ
- 関数の中の関数
- 状態を保持する関数



##おわり

以上です。
ありがとうございました。
（実はQiita初投稿）



##参考

スライドver.
http://shuuuuun.github.io/study-closure/
ほぼおなじ。


Wikipedia
https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3
わからない。でも理解してから見るとちょっとわかる。

はてなキーワード
http://d.hatena.ne.jp/keyword/%A5%AF%A5%ED%A1%BC%A5%B8%A5%E3
わからない。でも理解してから見るとちょっとわかる。

猿でもわかるクロージャ超入門
http://dqn.sakusakutto.jp/2009/01/javascript_5.html
超わかりやすい。

うひょひょ
http://uhyohyo.net/javascript/9_5.html
わかりやすい。

JavaScriptでクロージャ入門（Qiita）
http://qiita.com/takeharu/items/4975031faf6f7baf077a
なるほど。

MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures
ふむふむ。

クロージャを使ったプライベート関数の隠蔽について
http://satoshi.blogs.com/life/2007/12/javascript-2.html
なるほどなるほど。