頑張らないために頑張る

ゆるく頑張ります

JavaScriptの即時関数についてメモ

Posted at — Aug 8, 2020

概要

プログラミング言語における関数は、一度どこかで宣言をしてから別の所でその関数を呼び出すことにより実行できます。ただ、JSに関しては宣言と同時に実行が可能な即時関数という機能があります。

一度しか利用しないような処理を即時関数としてまとめておく、とにかく冒頭で実行させたい処理がある・・・というケースに使うかな。あとは、サンプル的に実行するのでわざわざ呼び出しすら記述したくない、とか。

なお、function()やアロー関数でも両方即時関数として記述できます。

記述方法

記述方法は関数を丸カッコで囲います。この囲い方に特徴があって、「関数を宣言しつつ、実行するようなコード」を記述しています。

((hoge)=>{console.log(hoge)})('hoge');

なにやらカッコがいっぱいあってややこしいですが、分解して考えれば問題ありません。

(hoge)=>{console.log(hoge)}

まず、この部分はアロー関数の宣言部分。これは「関数の宣言」部分として解釈できます。名前のない関数、つまり匿名関数を宣言しています。とりあえず、これ以降はこの部分を「F」として表記を簡略化してみましょう。すると残った部分はどうなるか、という話ですが。

(F)('hoge');

こうなります。

「F」で置き換えた部分と'hoge'という文字列が、それぞれ丸カッコで囲われています。このうち、'hoge'を囲っている部分は関数に渡す引数を記述しています。関数Fは引数を指定する必要がある関数なのでこのような記述になりますが、引数を必要としない関数に対しても丸カッコは省略できません。

ところで、関数は引数の有無こそあれ、実行のためのトリガーがなにかしら必要になります。宣言と実行を別に記述するような、普段の実装の場合はどう記述しているかを考えてみると、宣言した関数がXXXという名前である場合はXXX()というように記述して実行します。これが引数を必要とする関数である場合は、XXX(foo, bar, baz)というように記述し実行します。つまり、この()の部分が関数の実行の直接のトリガーになる、と考えられるわけです。ということは、このトリガーを匿名関数でも使えばいいわけです。

そんなわけで、さきほど記述した匿名関数のFに対しても同様に記述してみます。

F('hoge');

ただし、上記のような書き方では残念ながらエラーになります。これはJSの言語仕様で、冒頭にいきなりfunction()が来る関数や丸カッコの左側になにもないアロー関数、つまり匿名関数をそれ単体では書けないからです。ただ、逆に言えば冒頭に書かなければいいのであって、なにかしらの文字を冒頭に書いてやればいい、ということになります。

+function(){console.log('test')}()

というわけで書いたのがこれ。

冒頭に演算子の+を書くという、ある意味非常識極まりない記述方法ですがこれはJSだと実行可能です。これは、-とかでもいいし!でもいいです。ただし、この書き方はアロー関数では使えませんので念のため。ただ、function()の即時関数でも上記のような書き方をすることはほとんどありません。理由は、+のような演算子を記述することがバグの遠因となるかもしれないから。よって、大抵は算術の優先度を決める丸カッコを利用します

(function(){console.log('test')})();
(function(){console.log('test')}()); // この書き方でも大丈夫

つまりこうなります。この記述方法を匿名のアロー関数に適用したのが、最初の例です。

まとめ

これらの結果が即時関数の書き方なわけです。考え方がわかれば、ぱっと見よくわからない文法もなんとか納得できます。

それにしても、JSはホントに複雑怪奇だわ・・・。

参考

IIFE(即時実行関数式)

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

comments powered by Disqus