まとめ
JavaScript のカプセル化された匿名関数の構文の背後にある理由を説明していただけますか? これは機能する(function(){})();
のに、これは機能しないのはなぜですかfunction(){}();
?
私が知っていること
JavaScript では、次のように名前付き関数を作成します。
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
匿名関数を作成して変数に割り当てることもできます。
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
匿名関数を作成し、それを括弧で囲んですぐに実行することで、コード ブロックをカプセル化できます。
(function(){
alert(2 + 2);
})();
これは、Greasemonkey スクリプトや jQuery プラグインなどのように、モジュール化されたスクリプトを作成するときに、現在のスコープまたはグローバル スコープが競合する可能性のある変数で乱雑になるのを防ぐのに役立ちます。
これで、なぜこれが機能するのかが分かりました。括弧は内容を囲み、結果のみを公開します (これを説明するより良い方法があると思います)。たとえば、 のようになります(2 + 2) === 4
。
わからないこと
しかし、なぜこれが同じように機能しないのか理解できません。
function(){
alert(2 + 2);
}();
それを私に説明してもらえますか?
ベストアンサー1
FunctionDeclaration
これは として解析されており、関数宣言の名前識別子は必須であるため、機能しません。
括弧で囲むと として評価されFunctionExpression
、関数式に名前を付けることも、付けないこともできます。
a の文法はFunctionDeclaration
次のようになります。
function Identifier ( FormalParameterListopt ) { FunctionBody }
そしてFunctionExpression
s:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
ご覧のとおり、Identifier
(Identifier opt ) トークンはFunctionExpression
オプションなので、名前が定義されていない関数式を使用できます。
(function () {
alert(2 + 2);
}());
または名前付き関数式:
(function foo() {
alert(2 + 2);
}());
括弧(正式にはグループ化演算子) は式のみを囲むことができ、関数式が評価されます。
2 つの文法生成物は曖昧になる可能性があり、次のようにまったく同じに見えることもあります。
function foo () {} // FunctionDeclaration
0,function foo () {} // FunctionExpression
パーサーは、それが出現するコンテキストに応じて、それがFunctionDeclaration
か かを認識します。FunctionExpression
上記の例では、2番目は式です。カンマ演算子式のみを扱うこともできます。
一方、FunctionDeclaration
は実際には、いわゆる「Program
」コード、つまりグローバル スコープの外側のコード、およびFunctionBody
他の関数の の内側にのみ出現する可能性があります。
ブロック内の関数は予期しない動作を引き起こす可能性があるため、使用を避ける必要があります。例:
if (true) {
function foo() {
alert('true');
}
} else {
function foo() {
alert('false!');
}
}
foo(); // true? false? why?
上記のコードは実際には を生成するはずですSyntaxError
。Block
にはステートメントのみを含めることができます (ECMAScript 仕様では関数ステートメントは定義されていません) が、ほとんどの実装では許容されており、単に 2 番目の関数 (アラートを出す関数) が使用されます'false!'
。
Mozilla 実装 (Rhino、SpiderMonkey) の動作は異なります。これらの文法には非標準のFunction Statement が含まれており、関数は の場合のように解析時ではなく実行時に評価されますFunctionDeclaration
。これらの実装では、最初に定義された関数を取得します。
関数はさまざまな方法で宣言できます。以下を比較してください:
1- で定義された関数関数変数multiplyに割り当てられたコンストラクタ:
var multiply = new Function("x", "y", "return x * y;");
2- multiplyという名前の関数の関数宣言:
function multiply(x, y) {
return x * y;
}
3- 変数multiplyに割り当てられた関数式:
var multiply = function (x, y) {
return x * y;
};
4-変数multiplyに割り当てられた名前付き関数式func_name :
var multiply = function func_name(x, y) {
return x * y;
};