JavaScriptと YUI の両方が初めてです。 YUIライブラリの例では、この構成の多くの使用法を見つけることができます。
(function() {
var Dom = YAHOO.util.Dom,
Event = YAHOO.util.Event,
layout = null,
...
})();
最後の括弧は、宣言の直後に関数を実行することだと思います。
...しかし、関数宣言を囲む前の括弧のセットはどうでしょうか?
それは範囲の問題だと思います。それは、内部変数を外部関数や場合によってはグローバルオブジェクトに対して隠すことです。それは...ですか?より一般的には、これらの括弧の仕組みは何ですか?
これは、自己実行型の匿名関数です。最初の括弧のセットには実行される式が含まれ、2番目の括弧のセットはそれらの式を実行します。
親ネームスペースから変数を非表示にしようとする場合に便利な構造です。関数内のすべてのコードは、関数のプライベートスコープに含まれています。つまり、関数の外部からはまったくアクセスできず、本当にプライベートになります。
見る:
Andy Hume gave 答え、もう少し詳細を追加したい。
このコンストラクトを使用すると、独自の評価環境またはクロージャーを持つ匿名関数を作成し、すぐに評価します。これの良い点は、匿名関数の前に宣言された変数にアクセスでき、既存の変数を誤って上書きせずにこの関数内でlocal variablesを使用できることです。
JavaScriptではデフォルトですべての変数がグローバルであるため、varキーワードの使用は非常に重要ですが、キーワードを使用すると、新しいlexically scoped変数、つまり、コードで表示できます2つの波括弧の間。この例では、基本的にYUIライブラリのオブジェクトに短いエイリアスを作成していますが、より強力な用途があります。
コード例を示したくないので、ここでは簡単な例を使用してクロージャを説明します。
var add_gen = function(n) {
return function(x) {
return n + x;
};
};
var add2 = add_gen(2);
add2(3); // result is 5
ここで何が起こっていますか?関数add_genでは、単に引数nを引数に追加する別の関数を作成しています。トリックは、関数パラメーターリストで定義された変数で、varで定義された変数のように、レキシカルスコープの変数として機能することです。
返される関数は中括弧で定義add_gen関数であるため、nの値にもアクセスできますadd_gen関数の実行が終了した後、このため、例の最後の行を実行すると5が取得されます。
字句スコープの関数パラメーターの助けを借りて、匿名関数でループ変数を使用することから生じる「問題」を回避できます。簡単な例を挙げます。
for(var i=0; i<5; i++) {
setTimeout(function(){alert(i)}, 10);
}
「期待される」結果は0から4までの数字ですが、代わりに5の4つのインスタンスを取得します。これは、setTimeoutの匿名関数とforループがvery samei変数を使用しているため、関数が評価されるまでにiは5になります。
関数パラメータがレキシカルスコープであるという質問と事実のテクニックを使用することで、素朴に期待される結果を得ることができます。 (このアプローチを その他の回答 で使用しました)
for(var i=0; i<5; i++) {
setTimeout(
(function(j) {
return function(){alert(j)};
})(i), 10);
}
外部関数の即時評価により、各反復でjという名前の完全に独立した変数を作成し、iの現在の値は- copiedこの変数に入力すると、最初の試行から単純に予想された結果が得られます。
http://ejohn.org/apps/learn/ にある優れたチュートリアルを理解して、クロージャをよりよく理解することをお勧めします。ここで非常に多くを学びました。
...しかし、すべての関数宣言を囲む前の丸い括弧についてはどうでしょうか?
具体的には、JavaScriptに 'function(){...}'構造をインラインの匿名関数式として解釈させます。括弧を省略した場合:
function() {
alert('hello');
}();
JSパーサーは 'function'キーワードを見て、次の形式の関数statementを開始していると想定するため、構文エラーが発生します。
function doSomething() {
}
...そして、関数名のない関数ステートメントを作成することはできません。
関数式と関数ステートメントは、まったく異なる方法で処理される2つの異なる構成要素です。残念なことに、構文はほとんど同じなので、プログラマーを混乱させるだけでなく、パーサーでさえあなたが何を意味しているのかを理解するのが困難です!
アンディ・ヒュームと他の人が言ったことをフォローアップするための冗談:
無名関数を囲む「()」は、ECMA仕様のセクション11.1.6で定義されている「グループ化演算子」です。 http://www.ecma-international.org/publications/files/ECMA-ST /Ecma-262.pdf 。
ドキュメントから逐語的に:
11.1.6グループ化演算子
生産 PrimaryExpression :( 表現 )は次のように評価されます。
このコンテキストでは、関数は式として扱われます。
この件に関するいくつかの考慮事項:
括弧:
ブラウザ(エンジン/パーサー)は、キーワード関数を
[optional name]([optional parameters]){...code...}
したがって、function(){}()のような式では、最後の括弧は意味がありません。
今考えて
name=function(){} ; name() !?
はい、括弧の最初のペアは匿名関数を強制的に変数(格納された式)に変え、2番目は評価/実行を開始するため、( function(){} )()理にかなっています。
ユーティリティ:?
ロード時に一部のコードを実行し、特に名前の競合が発生する可能性がある場合に、使用される変数をページの残りの部分から分離するため。
Eval( "string")を置き換えます
(新しいFunction( "string"))()
「= ?:」演算子の長いコードを次のようにラップします。
結果= exp_to_test? (function(){... long_code ...})():(function(){...})();
最初の括弧は、操作の順序を示します。関数定義を囲む括弧のセットの「結果」は関数そのものであり、実際に、2番目の括弧のセットが実行されます。
なぜそれが有用なのかについては、JavaScriptウィザードだけでは考えがつきません。 :P
この質問 を参照してください。関数名を使用する場合、括弧の最初のセットは必要ありませんが、名前のない関数にはこの構造が必要です。括弧は、コードを参照するときに自己呼び出し関数を表示していることをコーダーが認識できるようにします(1つのブロガーを参照してください- ベストプラクティスの推奨 )。