Caution

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

  1. トップページ
  2. JavaScript中級編 - 即時関数の使い方と構造について

即時関数の使い方と構造について

みなさまどうもこんにちわ。

続きまして『即時関数』というものを解説していきたいと思います。即時関数とは以下のようなものです。

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

ぱっと見、括弧だらけでわけ分からないですよね。しかし、この記法は非常に強力なので絶対に覚えるようにしてください。構造が分かればそんなに難しいものではありません。

この『即時関数』はその名の通り『即時実行される無名関数』となります。即時実行できる無名の関数とはつまり、『グローバルの名前を全く潰さず、ローカルのスコープを作り出しそのまま処理を実行することができる』という事になります。なので超便利です。

では記法を確認していきましょう。まず前回の記事の『無名関数』を思い出してみましょう。『function(){}』ってやつですね。前回の記事でもちょろりと解説しましたが、JavaScriptでは冒頭に『function』って書かなければ関数定義文にはならないというバグのような謎仕様になっています。

なので以下のように意味のない『+』を文頭につけると『無名関数』が定義できます。

+function(){
    console.log("無名関数だよ!");
}

しかし、上記の文は『無名関数』を定義しただけです。実行はされませんし、名前が無いため後から呼び出すこともできない全く意味のない記述になります。

ではここでJavaScriptで関数を実行させる方法を思い出してみましょう。そうです、『()』を付ければいいんでしたね。『()』はJavaScriptにおいて関数実行のトリガーのようなものです。

ということは上記の文に『()』を付ければそのまま動かせるんじゃね?と考えた方、大正解です。

+function(){
    console.log("無名関数だよ!");
}();

これ、動かせます。というわけで『即時関数』の完成です。

上記の『即時関数』の中は関数スコープとなるため内部で『var』などをつけて変数やオブジェクトを定義すればちゃんとローカルオブジェクト扱いとなります。グローバルの名前を潰してしまったりすることはありません。

+function(){
    var x = 0; // ここは関数の中なのでこれはローカル変数となります。
}();

console.log(x); // グローバル変数の『x』は定義してないのでちゃんとエラーになります。

いかがでしょうか。このように名前を付けずにローカル関数の領域を作成できるので超強力な記法です。

さて、上記の『+』を使った『即時関数』も立派な『即時関数』なのですが実はちょっと問題があります。『+』を使っているということです。

JavaScriptで値の横に『+』と置くと、すべて数値に変換されるという処理が行われます。数値に変換できないものは『NaN』という値に変換されます。

『NaN』(ナン)とは、『Not A Number』の略で、ただの数値ではないことを表す特別な値です。

『return文』のないJavaScriptでの関数は『undefined』が返ってくるのでしたね。ということは『+』と置くと『undefined』が『NaN』となってしまうということです。

var hoge = +function(){ // return文がないため通常は『undefind』が返ってきます。しかし『+』があるため『NaN』に変換されます。
    console.log("無名関数だよ!");
}();

console.log(hoge); // 『NaN』と出力されます。

余計な処理が走ってしまっているのでちょっと使い勝手が悪いです。意図せぬミスの原因になりそうですね。

さて、では最初に紹介した『即時関数』を再度確認してみましょう。先ほどの『+』を使った『即時関数』とはちょっと違っていますね。

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

どうやら『()』を使っているようです。さて、この『()』は何の括弧だろう、というと算術の優先度を調整する『()』です。ちょっと数学を思い出してみましょう。以下のような数式があったとします。

1 + 2 * 3

これは乗算が優先されるため、『2 * 3』が行われた後に『+1』され答えは『7』になります。

先に『1 + 2』を計算させたい場合は以下のようにしますね。

(1 + 2) * 3

こうすると『1 + 2』が先に計算され、答えは『9』になります。

この括弧は全体を意味なく包んでしまっても問題ありません。以下のような形ですね。プログラミングでも同じです。

((1 + 2) * 3)

この括弧はあくまでも算術(演算)の順番を決めるだけの括弧なので中身に影響を与えません。

ということは『function(){}』を『()』で包んでしまえば中身に影響を与えることなく『無名関数』が定義できるということです。

というわけで中身に何も影響を与えない『無名関数』の完成です。

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

そして関数を実行させるための『()』をつければ『即時関数』となります。

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

ちなみに全体を包む『()』の位置はちょっと変えてもOKです。

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

どちらでも問題ないですが、最後の『即時関数』の方が若干多数派かもしれません。

さて、最後にちょっと応用技です。先ほどJavaScriptでは『()』を付ければそのまま関数を実行できる、というお話がありましたね。なので『return文』と組み合わせると演算させた結果などを他の処理に返すことができます。

以下のような感じですね。

console.log(function(){ // 実行すると『3』と出力してくれます。
    return 1 + 2;
}());

ちょっと慣れないと意味が分からないかもしれませんが括弧の数に注目です。『console.log()』の引数の中で『即時関数』を実行し『1 + 2』の結果を『return文』で返させています。ちょっとむずかしいかもしれませんがこの記法も超強力なので覚えておくようにしましょう。

ちなみに文頭に『function』と記述しているわけではないので『無名関数』全体を包む『()』は記述する必要ありません。

// エラーになることはありませんが、文頭に『function』と記述しているわけではないので以下のように無名関数全体を包む『()』は書かなくてOKです。
console.log((function(){
    return 1 + 2;
})());

『即時関数』は関数なので引数もちゃんと渡すことができます。以下のサンプルを確認してみましょう。

(function(x, y){ // 仮引数『x』には『1』が、仮引数『y』には『2』が入ります。
    console.log(x + y); // 『3』が出力されます。
})(1, 2); // 引数に『1』と『2』を渡します。

かなり構文がややこしくなっているので慣れないとかなり大変かもしれません。即時で実行する関数なので引数と仮引数を同時に記述しなくてはいけないということも紛らわしいところです。

しかし『即時関数』に引数を渡すという記法は非常に強力です。以下のサンプルをみてください。

var x = 0; // これはグローバル変数『x』

(function(x){ // グローバル変数『x』の値『0』を仮引数『x』で受け取ります。
    ++x; // 仮引数『x』に『1』を加算します。
    console.log(x); // 『1』が出力されます。
})(x); // グローバル変数『x』を渡します。この時点の『x』は『0』です。

console.log(x); // 即時関数で加算された『x』は仮引数『x』なのでグローバル変数『x』の値は変わりません。『0』と出力されます。

グローバル変数を使っているにも関わらずグローバル変数の値に変化がない、というとても素敵な処理になっています。しかもグローバル変数とローカル変数で同じ名前(識別子)を使えていることにも注目ですね。

『即時関数』は『()』だらけなので最初は読みとくのが大変かもしれませんが、慣れるとサラリと読み解くことができるようになりますので頑張ってください。

というわけでお疲れ様でした、『即時関数』についての基本的な解説は以上となります。いかがでしたでしょうか。ぱっと見、意味の分からない記述な気がしますが紐解いていくとそんなに難しい構文ではないかと思います。

私も外人さんのソースコードで初めて『即時関数』を見た時は「こんな記述方法があったのか!」と驚いた反面、バグ技のような気がしてしまいなるべく使わないようにしていたのですが、いつしか公式サイトなどでも『即時関数』が使われるようになり、その強力な機能性から今ではJavaScriptの構築にあたって『即時関数』はなくてはならないものとなっています。というか最初にこれを見つけた人はすごいです。

なのでみなさんもバリバリ使いこなしてしまってください。

続いての記事では『参照渡し』についてやっていきたいと思います。引き続き頑張っていきましょう。ではー。

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

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

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

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