JavaScriptで、変数名を省略する記法
無名関数について説明する前に、JavaScriptで変数名を省略する書き方を説明します。
例えば、JavaScriptで今年の西暦を調べるには、次のようにします。
var day = new Date;
var year = day.getFullYear();
これは、dayという名前の変数の宣言を省略して、カッコで括っても同じです。つまり、下のようにも書けます。
var year = (new Date).getFullYear();
カッコの中で、new Dateを行ない、その値のメソッドgetFullYearを使って処理をしています。
これは、変数dayを1回しか使わないのであれば、こういう書き方も出来るという例です。
JavaScriptでの関数の宣言方法は2通り
JavaScriptで関数を宣言する方法は、2通りあります。
方法1. function hoge(){ /*処理*/ }
方法2. var hoge = function(){ /*処理*/ }
上の2つは、どちらもhogeという名前の関数を宣言しています。
JavaScriptの無名関数
関数宣言の方法2を使って、下のような処理をするとします。
var hoge = function(){ /*処理*/ }
var result = hoge();
これは、今年の西暦を調べたときのように、下のように書けます。
var result = (function(){ /*処理*/ })();
このような、名前を宣言していない関数のことを無名関数と言います。無名関数には、引数も与えられます。
var result = (function(num){ return num * 10; })(2); /* resultは20になる */
通常、関数は何度も処理を繰り返すために作るので、名前をつけて宣言しますが、1回しか使わない関数の場合は、こういう書き方も出来ます。
1回しか使わない関数とは
1回しか処理を行なわないのであれば、関数にせず、そのまま処理を書いてもいいような気もします。では、HTMLの中で下のように書いたとします。
<script type="text/javascript">
var num = 2;
var result = num * 10;
</script>
これでも、resultは20になります。ですが、もし別の場所でも変数numが使われていたとしたらどうなるでしょう。
ブログでは、好きなようにブログパーツを設置できます。上の処理の前に別の人が作った、次のような内容のブログパーツを貼っていたとします。
いらっしゃいませ!あなたは<span id="elem"></span>人目のお客様です!
<script type="text/javascript">
var num = 1000;
window.onload = function(){
document.getElementById('elem').innerHTML = num;
};
</script>
この後に、先ほどの処理が行なわれると、グローバル変数のnumは、1000ではなく、2に書きかえられます。
window.onloadは、HTMLのすべてを読み終わってから動作しますので、ページ読み込み後に
「いらっしゃいませ!あなたは1000人目のお客様です!」
と表示されるはずのものが
「いらっしゃいませ!あなたは2人目のお客様です!」
と表示されてしまいます。これでは、あんまりではないですか?
こういう悲しい誤作動をなくすために、無名関数を使って、グローバル変数ではなく、ローカル変数にすることも出来ます。
無名関数を使って、関数を返す
無名関数を使って、よくやる手法で、複数回使う関数を、最初に選択しておくという方法があります。例えば下の関数を見てみましょう。
var hoge = function(elem, event, func){
if(elem.addEventListener){
elem.addEventListener(event, func, false);
}else if(elem.attachEvent){
elem.attachEvent('on'+event, func);
}
}
この関数をそのまま使うと、呼び出す度にif文の処理をします。しかし、addEventListenerなのか、attachEventなのかは、変化するはずのない結論なので、下の様にすれば、if文の処理は最初の1回だけで済みます。
var hoge = (function(){
if(window.addEventListener){
return function(elem, event, func){
elem.addEventListener(event, func, false);
}
}else if(window.attachEvent){
return function(elem, event, func){
elem.attachEvent('on'+event, func);
}
}
})();