読者です 読者をやめる 読者になる 読者になる

JavaScriptの即時関数とは何か。意味やメリット、引数の使い方についてまとめてみた。

広告

どうも、ゴトーだ。

f:id:hogehoge223:20170208081817j:plain

最近は職業訓練がてらプログラミングの学習を毎日10時間くらい続けているのだが、そろそろプログラミング初心者に向けて記事も書いていこうかと思い、初めて検索流入を意識した内容のものにしてみた。
プログラミングをやっていない人には、何のことかさっぱり分からない内容なのは申し訳ない。

それと俺はまだプログラミング歴2週間強の素人なので、書いている内容に誤りなどがあれば生暖かく指摘して欲しい。

JavaScriptの即時関数とは

f:id:hogehoge223:20161109221042p:plain

自分が初めて即時関数を知ったのはドットインストールで、とりあえず囲っておきましょうみたいな感じで目にしたのが初めてだった気がする。
まずは細かい説明はさておき、このような構文のものを即時関数と呼ぶ。

(function() {
  // 実行内容
}());

このようなプログラムを書くと「// 実行内容」として書かれている箇所のプログラムが特に何もしてくても実行される。
即時に実行される関数だから、即時関数と呼ぶらしい。

最後の「()」という部分は意味ないように見えてこれがないと実行されないから必ず忘れずにつけよう。

ちなみにプログラムの全文がこれだけなら即時関数を使っても使わなくても何も動作に違いはない。
ただいくつかのプログラムが入り乱れるとたちまち変な動作をおこすし、使ってもデメリットは何もないからとりあえず使っておけというのが暗黙の了解らしい。

ガキの頃は準備運動なんてしなくてもいきなり走り出せたし大怪我なんてしたことはなかったが、高校生くらいからは負荷も上がって腰痛とかを慢性的に抱えるようになると運動前後のストレッチを入念にやらないとパフォーマンスがだせなくなったが、それと近いようなものなのかもしれんな。

これのありがたみがわからんうちはまだ所詮ヒヨッコ。
ありがたみがわかるまではとりあえず大人の言うことを聞いておけ、というメッセージだと俺は捉えたぜ。

なぜ必要なのか

これはスポーツでジュニアから一般世代に上がるときにも同じことが言えるのだが、最初は特に何も疑問を持たずに大人の言うことを鵜呑みにしている方が強い。
それが年齢が上がってくるとセルフコントロールして自分でパフォーマンスを上げていかないといけないから、だんだん考える奴が強くなってくる。

だから物分かりが良すぎるってのもどうかということで、俺はこの即時関数に疑問を持ってみた。
まあ疑問を持ったと言っても検索で調べて、自分で試す以上のことはしてないんだがな。

そして至った結論としては…JavaScriptはデフォルトだと全てグローバルな変数になってしまうので、即時関数で包むことで、その中だけで通用する変数や関数にしましょうということだ。

いわば即時関数はFacebookの「公開設定」だ。
Facebookは友達同士にしか見られていないなら内輪でちょっとヤバイ内容のものも投稿できるが、それを全体公開したらたちまち炎上しちまうだろ?
だから「友達まで」あるいは「自分のみ」といった公開設定しておいて、リスクマネジメントしておけよということになる。

では具体的な事例を見ていこう。

単純なケース

例えば俺は学習日記の中で、これまでマルバツゲームとオセロの2つのゲームを作った。
今の所は別々のページに分けているが、複合型アミューズメント施設のように1つのページに2つのゲームを載せたいとする。

その場合、即時関数を使っていなければすぐにバグで動かなくなるだろう。
なぜなら2つのゲームに「start()」という関数を使っているのだが、2つともグローバルな関数として存在していたら、そのstart()はどっちのゲームを始めるものなのかわからんぜよ…ということになってしまうからだ。

JavaScriptではファイルを分割していても、HTMLから読み込む時に即時関数に包まれていないものはグローバルな変数・関数になってしまう。
だから「マルバツゲームのJSファイル」「オセロのJSファイル」と2つ読み込んでいても、それぞれが即時関数の中に入っていなければ、2つに共通する変数や関数名が入っていたらバッティングしてしまうんだ。

それを解決するにはただ即時関数で包めばいい。簡単だろう?

(function() {
  // マルバツゲーム
}());

(function() {
  // オセロの実行内容
}());

例えばこのように変数名や関数名が競合していても、即時関数の中であれば直感的に理解できるような結果になる。

(function() {
  var turn = -1;

  function start() {
    console.log('マルバツゲームの開始!!');
  }

  start();

  console.log(turn) --> -1
}());

(function() {
  var turn = 1;

  function start() {
    console.log('オセロゲームの開始!!');
  }

  start();

  console.log(turn) --> 1
}());

その他の使い方

調べていると「読み込まれた時に1回だけ実行される無名関数」みたいに説明されている事が多いが、実はこんな使い方もできるんだとか。
もっともイレギュラーなので実際にはあまり使われないらしいが。

引数を持たせられる

即時関数はこのように引数を持たせられる。

(function (count1, count2) {
  console.log(count1); --> 1
  console.log(count2); --> 2
})(1, 2);

名前をつけられる

即時関数は基本的に名前をつけずに一回限り実行するために使われるが、このように名前をつけることで複数回実行できるらしい。

(function shout(count) {
  console.log('クリリンのことかーーーーーーーー ')

  setTimeout(function () {
    shout(count);
  }, 1000);
}())

こうすると1秒ごとに「クリリンのことかーーーーーーーー」と叫び続ける。

合わせ技

なんか色々遊んでいたら、組み合わせてこんなこともできた。

(function shout(count) {
  console.log('クリリンのことかーーーーーーーー (スーパーサイヤ人' + count + ')')

  setTimeout(function () {
    count++;
    shout(count);
  }, 1000);
}(1))

こうすると「クリリンのことかーーーーーーーー」と叫ぶ度にスーパーサイヤ人のランクが上がっていく。
ドラゴンボールのゲームを作る時に是非参考にして欲しい。

f:id:hogehoge223:20161117114624p:plain

まとめ

とりあえず即時関数は使って損はないから使っておこう。
それとただ使うだけじゃなく疑問に思って色々調べていると、思わぬ発見があったりして面白い。

最初はJavaScript辛かったけど、クセを理解するとだんだん楽しくなってきた。
けど総じて見るとぶっちゃけ辛い。

プログラミングは忍耐のスポーツだが、その中にどれだけの自分のメッセージを込めるかが大事な気がする。
その点で言うと俺がやっていた陸上競技と似ているところがある。