Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. JavaScript中級編 - 無名関数 関数式と関数宣言

無名関数 関数式と関数宣言

みなさまどうも。

続きまして『無名関数』(匿名関数)についてやっていきましょう。超重要項目となります。

これまでの当サイトの記事で『無名関数』はすでに何度か出てきています。今回の記事ではもうちょっと奥深くまで解説していきたいと思います。まずは『無名関数』を代入して関数の定義を行うことについての解説から始めます。

これまで紹介した関数定義の方法として大きく『関数宣言』と『関数式』(関数リテラル)がありました。
※ネーミングについては正式に決まっているものではないので参考書などで違っている場合があります。

関数宣言は以下のようなパターンで、

function hoge(){
    // ここに処理
};

関数式は以下のようなパターンになります。

var hoge = function(){
    // ここに処理
};

これまでの当サイトで紹介しているほとんどのサンプルソースでは初心者の方に分かりやすいように関数宣言の方を使ってきました。

しかし、実際のJavaScriptのソースコードでは関数式の方が多数派です。その理由は前回の記事で解説した『ホイスティング』が起こらない、というメリットがあるからです。

それらについて解説していきたいと思います。

まず関数式の記述方法ですが『function(){}』という無名の関数を代入して関数を定義する、という記述になります。この『function(){}』が『無名関数』と呼ばれる部分になりますので覚えておいてください。あと関数定義の時と違っておしりの『;』が必要になりますので注意です。JavaScriptでは『;』が自動補完されますので書き忘れても問題がでることはほとんどありませんが念のため書いておくようにしましょう。

引数を加えたい場合は以下のような感じです。『無名関数』の『()』の中に記述します。

var hoge = function(x, y){
    console.log(x, y);
};

実行させる際は関数定義された関数も関数式で定義された関数も変わりません。上記の場合ですと『hoge(0, 1);』といった感じになりますね。

var hoge = function(x, y){
    console.log(x, y);
};
hoge(0, 1); // 実行させる場合は同じ記述です。

さて、では『ホイスティング』についてみていきましょう。まずは関数宣言で定義された関数の場合です。以下は関数『hoge』の定義の前に関数『hoge』を実行させています。

hoge();

function hoge(){
    console.log("hoge");
}

さて、これを実行させると問題なく『hoge』と出力されます。関数『hoge』の定義の前に関数『hoge』を実行させているのにエラーにならないのが不思議ですね。

このように関数宣言で定義された関数はJavaScriptのファイルを取得し、解析(レンダリング)が終わった瞬間に生成されてしまうため、宣言される前から実行することができます。

前回の記事で解説した『ホイスティング』の時のようにかなり気持ち悪い感じがありますね。想像とかけ離れた動きなので思わぬミスを引き起こすかもしれません。

対して関数式の場合をみてみましょう。以下も同じく関数『hoge』の定義の前に関数『hoge』を実行させています。

hoge();

var hoge = function(){
    console.log("hoge");
};

これを実行させてみると、「『hoge』を関数として実行できないよ!」とちゃんとエラーになります。

このように関数式での関数の定義は代入処理が行われた時に初めて定義されますので巻き上げ処理は行われません。恐らく、大多数の方の想像通りの動きをしているのはこちらの関数式の方だと思います。

なのでJavaScriptの構築では関数式の方がよく使われています。みなさまも特別な理由がない限り関数式の方を使っていくと良いかもしれません。

関数式で関数の定義を行う際、名前をつけた関数式でもOKだったりします。

var hoge = function hoge2(){
    console.log("hoge");
};

ちょっとパッと見ると意味がわからないかもしれません。

関数『hoge2』の実態はただの関数オブジェクトになりますので関数オブジェクト部分だけ関数『hoge』として代入されているような形です。

上記の場合、関数『hoge』と関数『hoge2』が存在していますが関数『hoge2』はローカルの関数となりますので外から実行することはできません。

var hoge = function hoge2(){
    console.log("hoge");
};
hoge(); // これは実行できます。
hoge2(); // これはエラーです。

なのでなにもメリットはないような気がしますが、実は関数式が実行される前に自分自身を実行できるというトリッキーな動きをさせることができます。

var x = 0; // グローバル変数『x』に『0』を代入します。
var hoge = function hoge2(){
    console.log("hoge");
    if(x === 0){ // グローバル変数『x』が『0』の時のみ実行させます。つまり一回だけ処理させます。
        ++x; // グローバル変数『x』に『1』を足します。
        hoge2(); // 自分自身を実行します。
    }
};
hoge();

上記のパターンは『return文』とかと組み合わせると非常に面白い処理を構築できたりします。

ちなみにプログラミングでは上記のような自分自身を実行させたりするものを『再帰的処理』と呼ばれる場合があります。こちらも覚えておくと良いかもしません。

(´-`).。oO(ちなみに上記のサンプルのif文を取ると無限ループ処理になりますのでご注意を...)

続いて『無名関数』の注意点をみていきたいと思います。

まず『function(){}』といきなり書くとダメです。エラーになっちゃいます。

function(){
    // これはダメです。
}

これは文頭に『function』と書くと関数定義の文だと判断されてしまい、関数定義文では『function』に続けて関数名を記述しなければならないので文法エラーとなってしまいます。

「なら文頭に『function』と記述しないようにすれば『無名関数』が定義できちゃうんじゃね?」と考えた方いらっしゃるかもしれません。実はまさにその通りです。

+function(){
    // これ動かせます
}

上記のわけ分からない構文、動かせちゃいます。

JavaScriptでは『+』をぽんと置くと置かれた値を数値に変換してくれる(数値に変換できない場合は『NaN』という値になります)のですが、その構文を利用して『+function』とすると普通に『無名関数』を生成できてしまいます。

個人的にこれは想定外の一種のバグのようなものだったのではないかと考えているのですが、昨今ではこのバグ?を利用した『即時関数』というものが非常に良く使われています。『即時関数』については次の記事で解説していきますのでみなさんはとりあえず『文頭にfunctionって書かなければ無名関数として定義できる』ということを覚えておいてください。

さて、それを踏まえてちょっと『setTimeout()』を思い出してみましょう。『setTimeout()』の解説でもちょろりとサンプルソースを載せましたが、『無名関数』を使うと関数名の付いた関数を定義させずに『setTimeout()』を実行することができます。

以下のサンプルをみてください。

hoge = function(){
    alert("3秒経ちました!");
};
setTimeout(hoge, 3000);

上記はただ3秒後に『3秒経ちました!』とアラートダイアログを出すだけの処理になります。この処理に使われている関数『hoge』は再度呼び出す必要がないとしましょう。

再度呼び出す必要がないにも関わらず関数『hoge』を定義してしまっています。つまり今後、関数名や変数名などに『hoge』は使えません。上書きしちゃえばOKかもしれませんが、他の領域で使われている処理に対して意味なく干渉してしまうのはプログラミングのお作法に反します。

そんなときに『無名関数』を使用します。『無名関数』ならば名前を定義しないのでグローバルで使える名前を減らすことなく処理を構築することができます。

『文頭にfunctionって書かなければ無名関数として定義できる』ので『setTimeout()』の引数の中で使ってしまいましょう。

setTimeout(function(){
    alert("3秒経ちました!");
}, 3000);

いかがでしょうか。このように『無名関数』は名前を定義せずに関数オブジェクトを生成できるため非常に強力な記法となります。

JavaScriptでのプログラミングでは一度しか実行する必要がない処理を構築することが多いので『無名関数』の使用機会はかなり多くなるかと思います。

というわけで以上となります。続いての記事では先程も出てきた『即時関数』について解説をしていきたいと思います。引き続き頑張っていきましょう。ではー。

この記事は桜舞が執筆致しました。

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

ISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。