JavaScriptの関数(ラムダ関数とかクロージャーとか)
知ってて当然?初級者のためのJavaScriptで使う即時関数(function(){...})()の全て - 三等兵の記事を読んだ後に当記事を読むこと推奨。
ブックマークコメントを見ていて、用語の使い分けが気になったので書いておこうと思う。
無名関数かクロージャーが一般的じゃないのか?即実効関数とか使い捨て関数なんて初めて聞いた。
「即時関数」を言い表したいときに「匿名関数」とか「クロージャー」というのは不相応。
「匿名関数」
これは単に名前の付いていない関数を表す言葉であって、定義後に即実行する関数を指すとは限らない。また、記事中でも言及されているが、名前つきの関数でも「即時関数」は作成可能である。
「クロージャー」
クロージャーってのは宣言された時点のスコープを保持する関数のこと(静的スコープ)。『宣言された時点』というのが重要で、実行時ではない。これにより、どこで実行されようとも同じ結果を期待できる。(thisに関してはここでは言及しないよ)
JavaScriptにおいて全ての関数はクロージャーである。よって、これも「即時関数」を言い表すのには不相応。
「ラムダ関数」
ついでに「ラムダ関数」に関しても触れておこう。
数学の分野だと思うが、「ラムダ計算」というものがある。関数をラムダ(λ)を使って表すやり方だ。これをプログラミングでできるようにするためには関数を変数と同等に扱える必要が出てくる。
JavaScriptでは、この特徴を持ってますよね。変数の様に、代入したり、返り値として用いたり、引数として渡せたり等々。
もう少し突っ込んで考えてみると、変数の様に扱えるとなるとコード上のいろんな場所で関数が行き来することになる。すると、実行時のその関数のスコープってどうなるの? と疑問が出てくるよね? 実行時のスコープで実行されると意図しない変数を参照しまったりで大変やりにくいこととなるのは想像に難くない。
そこで、「クロージャー」の登場。実行時ではなく、定義時のスコープで束縛してしまいましょう、となる。よって、ラムダ関数としての特徴を持つ関数は同時にクロージャーでもあることが多い。
JavaScriptの関数はラムダ関数でありクロージャーでもあるのだ。
ブログ記事などで関数のことをラムダ関数と言ったり、クロージャーと言ったりと混乱している人もいるだろうが、結局のところ同じなのである。ただ、分かって書いている人は書き表したい特徴によって書き分けているだけなのである(分からずにテキトウに書かれていることも多々見受けられるが...)。
さらに、JavaScriptの関数はラムダ関数なので、変数に代入可能である。以下の様にね。
var func = function f() { alert(1); }; func();
ここで関数へのアクセスはfunc
で可能だし、実行もfunc()
で可能だ。すると関数名のf
って必要なの? 必要なくない? 省略できるようにしてしまおうぜ。となるのは自然な流れだよね?
var func = function () { alert(1); }; func();
はい、匿名関数の出来上がり〜。
実際にこのような思考プロセスを辿ったかどうかは分からないが、こう考えると辻褄が合うのではなかろうか。
記事中で気になったこと
ちょい補足的なこと
今までの流れをぶったぎるような内容だけれど、実際のところFunction Statementという語句はありません。
たしかにECMAScriptの仕様上は存在しない。しかし、実装が仕様だけでなりたたないのが世の常であるw
MozillaのJavaScriptにはFunctionStatementなるものが存在する存在はしないが、そう呼べるものがある。これについてはFunction Expression Statements: Days on the Moonが詳しい。
実装依存だし、挙動もエンジンによってまちまちなので言及なしで構わないけど、一応補足として。
最後に
即時関数は個人的にはバッドノウハウだと思っている。JavaScriptにはブロックスコープのないため、苦肉の策といった印象を持っていたりする。まあ便利なので良く使わせてもらっているが。
次期ECMAScriptではブロックスコープを形成するletが盛り込まれるはずなので、使用頻度は少なくなっていくのかなぁとか思っていたり。