グローバル汚染を防ぐために
(function(){
// code ...
})();
で囲むけど、これのバリエーションっていろいろある。
// + を使う
+function(){
// code ...
}();
// - を使う
-function(){
// code ...
}();
// ! を使う
!function(){
// code ...
}();
// void を使う
void function()
{
// code ...
}();
ただこれはだめ。
function(){
// code ...
}();
// nodeだと「SyntaxError: Unexpected token (」となる
これはなぜダメなのかというと、このfunctionは「文」として、例とバリエーションは「式」としてみなされるからだそうだ。このあたり、仕様書を見て少し掘り下げてみることにする。
「ECMA2015」の「14.1 Function Definitions」を見ると、
14.1 Function Definitions Syntax FunctionDeclaration[Yield, Default] : function BindingIdentifier[?Yield] ( FormalParameters ) { FunctionBody } [+Default] function ( FormalParameters ) { FunctionBody } FunctionExpression : function BindingIdentifieropt ( FormalParameters ) { FunctionBody } . . .
functionは「FunctionDeclaration(function宣言)」と「FunctionExpression(function式)」の2種類ある。あ、「文」と「式」じゃなくて「宣言」と「式」なのか。で、「function式」として解釈されると例やバリエーションのように使えるのである。でもダメな例は「function式」に適合している。なぜだめなのか。それは「Expression Statement(式文)」に書いてある。
an ExpressionStatement cannot start with the function or class keywords because that would make it ambiguous with a FunctionDeclaration, a GeneratorDeclaration, or a ClassDeclaration.
「式」としてみなされるためにはfunctionを文頭におけないルールになっているのである。なぜこうなっているのかというと「function宣言」と紛らわしいから。文頭にfunction
を置くと「function宣言」とみなされる。
しかしなぜ「function宣言」だとダメで、「function式」で解釈されれば良いのかという疑問は残る。
これはJSの言語仕様上「FunctionDeclaration(function宣言)」と「FunctionExpression(function式)」の実行時評価に違いがあるからのようだ。(「のようだ」と書いたのは仕様書の解釈に少し自信がないため)
14.1.20 Runtime Semantics: Evaluationの項を読むと、「function宣言」の戻り値は「empty」である。
そして「function式の戻り値」は「closure」となっている。「closure」はFunctionオブジェクトである。FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } 1. Return NormalCompletion(empty). NOTE 1 An alternative semantics is provided in B.3.3. FunctionDeclaration : function ( FormalParameters ) { FunctionBody } Return NormalCompletion(empty).
FunctionExpression : function ( FormalParameters ) { FunctionBody } 1.If the function code for FunctionExpression is strict mode code, let strict be true.otherwise let strict be false. 2.Let scope be the LexicalEnvironment of the running execution context. 3.Let closure be FunctionCreate(Normal, FormalParameters, FunctionBody, scope, strict). 4. Perform MakeConstructor(closure). 5. Return closure.
つまり「function宣言」では「empty(空)」が返るので()
をつけるとNGであり、function式の戻り値はFunctionオブジェクトなので()
を付けてもOKなのである。
まとめると、
- ECMA Script 2015 の言語仕様により、文頭が
function
で始まる文は、「function宣言」になり、実行時評価後の戻り値が「empty」となるため、()
を付加すると文法エラーとなる。 - 「式(式文)」の途中に「function」が始まる場合は「function式」となる。「function式」の評価後の戻り値は「Functionオブジェクト」のインスタンスとなる。そのため
()
を付与して即時に実行することができる。
ということかな?