Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

2015/09/02

キーワード

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

クロージャとは?

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

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

???

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

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

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

・・・

わからない・・・

つくってみよう

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

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

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

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

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

num = 0;  // ←

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

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

スコープを切ろう

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

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

// 動かしてみよう。

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

できない。(そりゃそうだ)

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

そこでクロージャ。

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

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番目のコードをくっつけた感じ?

軽く解説

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

var countup = (function(){
    ...
})();

全体としては、即時関数を実行しその返り値を変数countupに代入しています。

変数numはこの外側の関数(即時関数)の中で宣言されています。


そしてその即時関数の返り値が、

return function(){
    return ++num;
}

関数になっている!

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

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

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

つまり、クロージャとは

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

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

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
なるほどなるほど。

shuuuuun
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした