web-dev-qa-db-ja.com

オブジェクト/関数/クラス宣言を囲む括弧は何を意味しますか?

JavaScriptと YUI の両方が初めてです。 YUIライブラリの例では、この構成の多くの使用法を見つけることができます。

(function() {
    var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    layout = null,
        ...
})();

最後の括弧は、宣言の直後に関数を実行することだと思います。

...しかし、関数宣言を囲む前の括弧のセットはどうでしょうか?

それは範囲の問題だと思います。それは、内部変数を外部関数や場合によってはグローバルオブジェクトに対して隠すことです。それは...ですか?より一般的には、これらの括弧の仕組みは何ですか?

284
user54692

これは、自己実行型の匿名関数です。最初の括弧のセットには実行される式が含まれ、2番目の括弧のセットはそれらの式を実行します。

親ネームスペースから変数を非表示にしようとする場合に便利な構造です。関数内のすべてのコードは、関数のプライベートスコープに含まれています。つまり、関数の外部からはまったくアクセスできず、本当にプライベートになります。

見る:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespacing

213
Andy Hume

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/ にある優れたチュートリアルを理解して、クロージャをよりよく理解することをお勧めします。ここで非常に多くを学びました。

140
bandi

...しかし、すべての関数宣言を囲む前の丸い括弧についてはどうでしょうか?

具体的には、JavaScriptに 'function(){...}'構造をインラインの匿名関数式として解釈させます。括弧を省略した場合:

function() {
    alert('hello');
}();

JSパーサーは 'function'キーワードを見て、次の形式の関数statementを開始していると想定するため、構文エラーが発生します。

function doSomething() {
}

...そして、関数名のない関数ステートメントを作成することはできません。

関数式と関数ステートメントは、まったく異なる方法で処理される2つの異なる構成要素です。残念なことに、構文はほとんど同じなので、プログラマーを混乱させるだけでなく、パーサーでさえあなたが何を意味しているのかを理解するのが困難です!

46
bobince

アンディ・ヒュームと他の人が言ったことをフォローアップするための冗談:

無名関数を囲む「()」は、ECMA仕様のセクション11.1.6で定義されている「グループ化演算子」です。 http://www.ecma-international.org/publications/files/ECMA-ST /Ecma-262.pdf

ドキュメントから逐語的に:

11.1.6グループ化演算子

生産 PrimaryExpression :( 表現 )は次のように評価されます。

  1. 評価の結果を返します 表現。これは、参照タイプの場合があります。

このコンテキストでは、関数は式として扱われます。

14
user484261

この件に関するいくつかの考慮事項:

  • 括弧:

    ブラウザ(エンジン/パーサー)は、キーワード関数を

    [optional name]([optional parameters]){...code...}
    

    したがって、function(){}()のような式では、最後の括弧は意味がありません。

    今考えて

    name=function(){} ; name() !?
    

はい、括弧の最初のペアは匿名関数を強制的に変数(格納された式)に変え、2番目は評価/実行を開始するため、 function(){} )()理にかなっています。

  • ユーティリティ:?

    1. ロード時に一部のコードを実行し、特に名前の競合が発生する可能性がある場合に、使用される変数をページの残りの部分から分離するため。

    2. Eval( "string")を置き換えます

      (新しいFunction( "string"))()

    3. = ?:」演算子の長いコードを次のようにラップします。

      結果= exp_to_test? (function(){... long_code ...})():(function(){...})();

6
bortunac

最初の括弧は、操作の順序を示します。関数定義を囲む括弧のセットの「結果」は関数そのものであり、実際に、2番目の括弧のセットが実行されます。

なぜそれが有用なのかについては、JavaScriptウィザードだけでは考えがつきません。 :P

4
Sean Edwards

この質問 を参照してください。関数名を使用する場合、括弧の最初のセットは必要ありませんが、名前のない関数にはこの構造が必要です。括弧は、コードを参照するときに自己呼び出し関数を表示していることをコーダーが認識できるようにします(1つのブロガーを参照してください- ベストプラクティスの推奨 )。

1
palswim