JavaScriptに無名関数というものも即時関数というものも構文としては存在しない

**【2019年3月26日追記】**

いつからは不明ですが、元ネタのTecaAcademyマガジンの記事が大きく修正されていました。ですので、下記内容の一部は現在の記事内容にあっていません。古い記事はWebArhiveあたりを探ってください。

---

[無名関数とは<おまけで即時関数も>](https://qiita.com/hiroshimaeasyryo/items/a270b00c420ed96f02f0)という記事を読んでいると所々引用文になっていた。引用元はどこなのかと探してみたところ、次の記事を見つけた。

[JavaScriptで即時関数を使う方法【初心者向け】 | TechAcademyマガジン](https://techacademy.jp/magazine/5530)

ちょっと酷い内容なので、突っ込んでいこうと思う。

なお、記事に合わせてES5レベルでの解釈をしているが、仕様書等は面倒だったのでES2018を参照している。

## 即時関数 ⊂ 無名関数 ？

> 即時関数は、無名関数と呼ばれる関数の一種です。

この一文だけで「やばい」と思った人はJavaScriptを語る資格があるから、安心してくれ。「その通り」と同意してしまった人は、ちゃんとした入門書を読み直した方が良いだろう。

無名ではない即時関数なんていくらでも作ることが出来る。

```js:JavaScript
(function hoge() {
    console.trace("trace");
})();
```

上を実行してみればわかるとおり、トレース情報に関数名として"hoge"が表示されるはずだ。即時関数であるにもかかわらず、無名でもなんでもない関数ができてしまった。

## 関数宣言は定義方法の一つにすぎない。

さて、元ネタTechAcademyマガジンに戻ってみよう。そこには関数の定義として次のような例が載っている。そのまま引用しよう。

```html:元ネタから引用
<script>
　function 関数名( ) {
　　処理
　}
</script>
```

なお、上のスペースは全角スペース(U+3000、和字間隔)だ。JavaScriptでは"Zs"カテゴリーのUnicode文字を空白(White Space)として扱うとしており、全角スペースも"Zs"カテゴリーであるため、空白として使うこと自体は仕様上問題はない。[^1]

[^1]: JavaScriptでは問題はないが、他の多くの言語では問題が発生する。一生JavaScriptだけしか触らないのであれば、別に構わないが。

まず、これは**関数宣言(Function Declaration)**と言われるものだ。関数定義(Function Definition)の一つであるが、これが全てではない。

その後、関数宣言の場合、宣言の後だけではなく、宣言の前にも使用できるとしているが、これは巻き上げ(hoisting)という現象による物だ。それ自体は良いのだが、この使用できるには二つの異なる意味がある。

* 関数名として現れる前に、定義されているかどうか？
* 関数として評価される(呼び出される)前に、定義されているかどうか？

この違いは大きいのだが、たぶん理解できていないだろう。

## 関数式は無名とは限らない。

次に無名関数として書かれるのが次のようなコードだ。

```html:元ネタから引用
<script>
　function( ) {
　　処理
　}
</script>
```

まず、「処理」の部分が正しく書かれていたとしても、エラーになるようなコードを出すのは止めて欲しい。`<script>`で囲っていなければ、断片であるとも言えるが、囲っているせいで、一つの正しい書き方だと思われてしまう。

それはさておき、さらに例を見ておこう。

```html:元ネタから引用
　<script>
  var sum = function (a,b){
    var result = a + b;
    return result;
  }
  var answer = sum(1,2);
  console.log(ancer);
</script>
```

インデントが揃っていないのは元ネタがそうであるからだ。なお、`ancer`のスペルミスも元ネタの通りだ。この`function (...) {...}`は**関数式(Function Expression)**と言われるものだ。確かに名前を書く必要は無いが、名前を書いてもかまわない。

```js:JavaScript
var sum = function sum(a, b) {
  var result = a + b;
  return result;
};
var answer = sum(1,2);
console.log(answer);
```

この記事を書いている人は、関数式を使った名前が無い関数を無名関数といっているようであるが、上のような関数は一体何関数になるのだろうか？これは関数宣言とは異なるので、**定義の前に評価することは出来ない**。

```js:正常に動作する。
var answer = sum(1,2);
console.log(answer);
function sum(a, b) {
  var result = a + b;
  return result;
}
```

```js:エラーになる。
var answer = sum(1,2);
console.log(answer);
var sum = function sum(a, b) {
  var result = a + b;
  return result;
};
```

関数式は名前が無くても良いから無名関数と呼んでしまうことには本質的な理解の不足があると言わざるを得ない[^2]。関数式でも名前有りに出来るのだ[^3]。そして、重要なのは、関数宣言は文だが、関数式は式であること、関数宣言はそれ全体が巻き上げられるが、関数式自体は巻き上げられないことだ。

[^2]: ES2015+では、`export default`でエクスポートする場合のみ、関数宣言でも名前を省略できる。その場合も無名関数と彼らは言うのだろうか？
[^3]: ES2015+では、無名の関数式であっても、最初の代入によってその変数名の名前が自動的に付けられる。デバッグ時などに`<anonymous>`とならないようにするためである。となると、無名関数とは一体何なのだろうか？

## 即時関数という構文はない。

元ネタでは最後に即時関数の話が出てくるのだが、何のことはない、これは関数式が式であるという特性を生かしたテクニックに過ぎない。関数式は式であるから、関数式が評価されたとき、関数オブジェクトを返す。その関数オブジェクトをそのまま実行しているに過ぎない。

そもそも、この話にはなぜ即時関数を使うのかという話が全く抜けている。1回しか使わないから即時にしたと言う話で落ちつこうとしているが、そもそも1回しか使わないなら、関数にする必要は無いはずだ。最後の例文は次のように書いても十分だ。

```js:JavaScript
var a = 1;
var b = 2;
var sum = a + b;
console.log(sum);
```

一体、彼らは何をしたかったのだろう。関数は複数回呼び出せるようにするから意味があるのであって、1回しか使わないならそもそも関数にする必要も無い。それでも関数にするのであれば、もっと明確な目的があるはずだし、それがなければ、意味の無いことをしているとしか思えない。

そもそも、無名関数の所で

> 1回きりしか使わない関数なので、名前をつける必要がない（=無名）

と言っている時点で、おかしい。関数式の本質はそこじゃない。式として関数オブジェクトを作れると言うことだ。関数を返す関数など、高階関数の話になってくると、その性質が重要であることに気づけるはずだ。

## 無記名かつ批判的なコメントが書かれる仕組みがない記事は等しく読む価値がない

この記事の問題点は、内容がひどいこともそうだが、この記事の公開スタイルそのものにある。問題点は二点だ。

* 無記名記事
* コメント不可

誰が書いたかは問題ではない。しかし、誰も責任を持とうとしないのは問題である。実名ではなく、ペンネームであったとしても、その著者名を付けるということは、その著者名に記事の責任が割り当てられる。それすらしないということは、便所の落書きと同じ、2chにはびこる名無しさんと同じである。

それよりひどいのは批判を受け付けないことだ。いや、紙媒体、本も批判を書くところがないというかも知れないが、今はAmazonレビューがあるし、著作名もはっきり書かかれているのだから、批判する場はいくらでもある。だが、電子媒体の記事でそういったコメントを受け付けないというのは、単に批判されたくないと言っているとしか見えない。マサカリが嫌だから、マサカリは受け付けませんという技術記事に読む価値はない。

結局の所、品質が悪い記事はどこかが批判を喰らうしかない。記事が匿名である限り、このような記事を平気で載せている所の品質が悪いと言うことにするしかない。最終的に、TechAcademyというサービスそのものの品質が悪い、運営元のキラメックス株式会社の技術力が低い、そう思われても仕方が無いと思う。