- 2007-12-18 (火)
- 技術
Life is beautiful: Javascript、クロージャを使ったプライベート関数の隠蔽についてを読んで。
JavaScriptで無名関数はちょくちょく出てくるんだけど、クロージャは一見するとなかなかの曲者。
説明としては、
親関数の外に参照が渡される内部関数をクロージャと呼ぶ
via: JavaScript クロージャとレキシカルスコープ - Backstage of theater.js
ふむふむ、なかなか難しいな。
では、Life is beautiful: Javascript、クロージャを使ったプライベート関数の隠蔽についてで紹介されていた内容と照らし合わせてみよう。
以下のソースを見てください。
<script language="JavaScript">
<!--
var code2name = (function(){
var mapping = {
'us': 'United States',
'ja': 'Japan',
'ko': 'Korea',
'ru': 'Russa',
'uk': 'United Kingdom',
'fr': 'France',
'cc': 'China',
'gw': 'Germany'
};
return function(code) { return mapping[code] || '(unknown)';};
})();
document.writeln(code2name('us')); // United Statesと出力
//-->
</script>
ちょっとソースは引用元より修正してありますが、ほとんど同じです。
実行すると「United States」と出力されるので、うまくマッピング処理がされているようだ。
では一旦クロージャの話の前に、気になるところを説明します。
それは・・・
<script language="JavaScript">
<!--
var code2name = (function(){
var mapping = {
'us': 'United States',
'ja': 'Japan',
'ko': 'Korea',
'ru': 'Russa',
'uk': 'United Kingdom',
'fr': 'France',
'cc': 'China',
'gw': 'Germany'
};
return function(code) { return mapping[code] || '(unknown)';};
})(); ←*1 これ!
document.writeln(code2name('us')); // United Statesと出力
//-->
</script>
*1 ここのカッコ()でその直前に定義した無名関数を実行する。
赤字のところ!
なんじゃこりゃ??
いやいや、大丈夫です。手順を踏めば簡単に理解ができます。
これは(function ~~)で囲われた無名関数を()で実行し、その結果を返すといった感じです。
つまり「code2name」に入るオブジェクトはreturn functionから始まる無名関数。
一番外側にある無名関数ではないのでそこが注意ポイントです。
これがクロージャの定義:「親関数の外に参照が渡される内部関数をクロージャと呼ぶ」にあたるのですね。
ではでは、↑の処理をもう少し分解して書き換えてみましょう。
<script language="JavaScript">
<!--
var code2name = function(){
var mapping = {
'us': 'United States',
'ja': 'Japan',
'ko': 'Korea',
'ru': 'Russa',
'uk': 'United Kingdom',
'fr': 'France',
'cc': 'China',
'gw': 'Germany'
};
return function(code) { return mapping[code] || '(unknown)';};
}; ←*1
var method = code2name();
method('ko');
//-->
</script>
*1 今度はカッコがありません。
これでも同様な結果になります。
(function ~~)()で事前に無名関数を実行していないので、一旦クロージャオブジェクトを取得する必要があります。
そして取得したクロージャオブジェクトを実行すれば同様の結果になる。
つまりこの部分です
var method = code2name(); // 一旦オブジェクトを取得する
う~ん、どっちのほうが分かりやすいんだろう。
一旦変数に入れる手間が大きいから(function ~~)()で事前に実行しておいたほうが良いかもしれないですね。
■クロージャを使う利点
Life is beautiful: Javascript、クロージャを使ったプライベート関数の隠蔽についてでも解説されていますが、↑のソースでmapping変数がありますが、これは不変的な連想配列なので1回作成すればよいものと考えます。
つまり一番外側の無名関数の中に隠蔽することによって、Javaでいうstaticなメンバの扱いになります。これはオーバヘッドが少なくてすむのできっちりメモリを意識したい人にはいいですね。
そしてクロージャの中でmapping変数が参照されているので、ガーベジコレクタがオブジェクトを破棄せずに残しててくれます。
これがレキシカルスコープですね。
レキシカルスコープの説明についてはJavaScript クロージャとレキシカルスコープこちらがとっても分かりやすかったです。
便利で面白いですが、ちょっぴり難しくなってしまうのは難点です。
- Newer: はてなハイクで遊んでみた
- Older: Rubyでのコンソール出力メソッドいろいろ
Comments:0
Trackback:0
- TrackBack URL for this entry
- http://hisasann.com/cgi-bin/mt/mt-tb.cgi/727
- Listed below are links to weblogs that reference
- 無名関数、クロージャ、そしてレキシカルスコープへ from HouseTect, JavaScript Blog


