ソーシャルボタンのJavaScriptでfunctionの前に「!」がついている理由

結論から言うと、単なる格好付けです。

以下説明。

主要なJavaScript (ECMAScript 5th)では、functionは2種類あります。

  • 文(Statement) *1
  • 式(Expression)

です。

所謂、「即時関数」と呼ばれるものはfunctionは式(Expression)である必要があります。

何故なら、関数実行を示す構文であるCallExpressionが式であり、それ以外存在しないからです。*2

JavaScript コードは文(Statement)の集合

JavaScriptのコードは文の集合と言えます。いきなり式が始まることはありえません。

とはいえ、

foo();
1 + 2;

といったものは成り立ちます。これは文(Statement)の解釈としてExpressionStatement(式を書いても良い)という、文が定義されているからです。

ともかく、文が成立しないとJavaScriptとしては構文エラーです。その中で式が突然出てきても良いのはExpressionStatementが成立しなければなりません。

ExpressionStatement

ExpressionStatementは定義では

ExpressionStatement :
  [lookahead ∉ {{, function}] Expression ;

と書かれています。

基本的にはExpression(式)ですが、[lookahead ∉ {{, function}] と書かれているように、先頭が{functionから始まってはならないという制限が設けられています。

この制限がないと、以下の様なコードがあった時、2種類の解釈が存在する事になってしまいます。

{
  a: "A"
};
  1. ブロック文
  2. オブジェクトリテラル
    • a: "A"はaプロパティに文字列"A" と解釈される
function foo () {};
  1. 関数宣言(FunctionDeclaration)
  2. 関数式(FunctionExpression)

これでは困ってしまうので、ExpressionStatementという文では、制限を設けているのです。

即時関数を作る

  • 即時関数の実現には function は式である必要がある
  • JavaScript のコードは文の集合であるが、ExpressionStatementという、いきなり式を書いても良い文法がある
    • ただし、{, functionが先頭に来てはいけない制限がある

逆に言えば、文の先頭にfunctionが来ない式を作れば良いのです。

!function(){}();
+function(){}();
-function(){}();
~function(){}();
(function(){}()); // Grouping Operator
0,function(){}();
a=function(){}();
[function(){}()]; // Array Literal
new function(){}; // 正確にはCallExpressionではなく、NewExpression だが
1+function(){}();
0|function(){}();
0&function(){}();
0||function(){}();
1&&function(){}();
++functtion(){}(); // 実行後エラーがでるけど
--functtion(){}(); // 実行後エラーがでるけど
void function(){}();
typeof function(){}();
delete function(){}();

と、まぁいろいろ考えられますね。

グルーピングがお勧め

さて、コードを書く上で、文法を守ルのは当然ですが、何かコーディング規約的なルールを持っていると迷いがないし、ルールに沿って書かれたコードは読みやすさに繋がるでしょう。

上記のようにいろいろ書けることを書いたけど、即時関数を作るルールを決めるとしたら、Groupingの(function(){}())をお勧めしたいと思います。
何故なら最も副作用が少ないからです。即時関数を書く時は、必ず()で囲む、という単純なルール(コーディング規約)設けられられます。
単項演算子などのやり方は、その式の返り値が変化させます。実行結果を得たい場合の障害となり、ルールが複雑化します。

また、オブジェクトリテラル中のプロパティ値にはAssignmentExpressionという式であって、ExpressionStatementである必要はありませんので、

var obj = {
  value: (function(){ }()),
};

と書かなくても

var obj = {
  value: function(){ }(),
};

でも良いことになります。しかし、それでも、()でグルーピングした方が良いと思います。メソッドを定義したのではなく、即時関数として結果を入れているんだという明示になり、読みやすさにも繋がるでしょうから。

最後に

!function(){ }();

という書き方は変則的であり、どういう意味があるかをきちんと理解していないと怪我をする代物だと思います。
それでもこの書き方をするのは、「こんな書き方も出来るんだぜ!?凄いだろ」という単なる格好付けだと思うわけです。


参考: http://www.koikikukan.com/archives/2013/06/12-003333.php

*1:文法上FunctionDeclarationというものがStatementと別途同列にあるけど、Statementに含めるとします

*2:NewExpressionもあるけど、どの道、式である