web-dev-qa-db-ja.com

ライブラリの一部をラップするこのコード構造とは何ですか?また、それは何に役立ちますか?

ライブラリを模倣して、次のコードを書くことができました。このコードは、_'c'_関数が割り当てられる_'a'_オブジェクトを作成しました。したがって、_'a'_を呼び出すには、c.a()を記述する必要があります。

また、この_'c'_オブジェクトにさらに関数を追加することができました。このコードで何が起こっているのかを理解したいと思います。通常のオブジェクト指向プログラミングのようには見えません。このタイプのJavaScriptプログラミングは何と呼ばれていますか?

_var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));
_
39
Atul

モジュールパターンです。そのパターンには多くのバリエーションがあります。そのため、実際に何が起こっているのかを理解することが不可欠です。1つを模倣することはできません。

このコードのポイントは、オブジェクトc(通常はグローバルライブラリ)を完成させることです。アプリケーションには、おそらく多くの類似したコードがあり、すべてがcの構成要素であり、それぞれが独自のファイルに含まれている可能性があります。

関数に引数として渡されるライブラリオブジェクトcがまだ存在しない場合(c === undefined)、作成されます。これにより、実行順序や事前に実行されたファイルに依存しないようにすることができます。

割り当ての右側は [〜#〜] iife [〜#〜] (即時呼び出し関数式)であり、これは即時呼び出しされる関数です。この構造の利点は、外部(グローバル)スコープを汚染することなく変数(たとえば、a関数)を宣言できるスコープを作成することです。ここでは、aがとにかく外部化されているため、要点は重要ではありませんが、モジュールは通常、いくつかの内部(プライベート)関数と変数に依存しています。

説明が必要な詳細:これらのファイルはすべてのように見えますが、新しい変数cを定義していますが、ここでは問題はありません。ファイルは連結されます。varステートメントは、新しい変数がすでに存在する場合、それを定義しません(変数は、宣言のポイントの前であっても、スコープ全体に対して、ここではグローバルに定義されます)。

これを書く別の方法は

var c = c || {}; // ensure the c variable is defined, and initialize its value it if necessary

(function() { // let's use an IIFE to have a protected scope and not pollute the global one
  function a() {
    alert(1);
  }
  c.a = a; // let's augment c
})();

これはおそらくより明確です

  • 2つのステップを明示的に分離します(IIFEを使用したc初期化とc完了)
  • 同じ名前の2つのc変数に依存しません
  • 冗長性が少ない
42
Denys Séguret

これは、すべての行の機能と、それを渡すと何が起こるかについてのコメントが追加された同じコードです。

//Here, we're defining a function that will return an object.
//its only parameter is named 'c'
//this is confusing, since the parameter has the same name as the global definition of the function.

//the var c definition is the global definition. the function parameter is not.
//so every reference to anything named 'c' inside the function definition is local. 
var c = (function(c) 
{
  //if c (the c we passed as a parameter) is not yet defined
  if (c === undefined) {
    //define c as an object
    c = {};
  }

  //define a function
  function a() {
    alert(1);
  }
  //attach it to the object
  c.a = a;

  //return the object
  return c;
}(c)); // call the constructor we just defined, using the global definition of `c`.
       // the first time we pass this point, c as a variable is still undefined.
36
Timothy Groote
_var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));
_

一歩一歩進んでいきましょう。

_var c =_

cという名前の変数を初期化します。この時点で、cという名前の変数がすでに初期化されている場合、cは、この宣言の最後に到達するまでのみその値を参照することに注意してください。

_( .... )_

これは、中にあるものはすべて式として扱われるべきであることを意味します。

function(c)

この「式」が引数を取る関数であることを意味します。今後、この引数は、関数が終了するまでcという名前で参照されます。したがって、関数スコープ外で宣言されたcという名前の変数には、ここから直接アクセスすることはできません。それがグローバルスコープ内にあり、グローバルスコープがたまたまウィンドウオブジェクトである場合でも、_window.c_と呼ばれることがあります。

if (c === undefined) { ... }

引数渡されたが未定義かどうかをチェックします。未定義の場合はtrueを返すため、ifブロック内にあるものを実行します。

_c = {}_

変数cを空のオブジェクトに設定します。したがって、引数が(渡された、または)未定義の場合は、ここで自分で定義します(そして、空のオブジェクトに定義します...)。

function a() { alert(1); }

aという名前の関数を宣言しました。これにより、数字の1が警告されます。これは単なる関数宣言であることに注意してください。この関数はまだ呼び出していません。

_c.a = a_

引数cには、作成したばかりの関数aを参照するaという名前のプロパティが割り当てられます。

_return c_

渡された引数に変更を加えた後、戻り値をcの最終値として関数から抜け出します。

_(fun...}(c))_

作成したばかりの関数を呼び出し、引数としてcの現在価値を渡します。関数を式として呼び出したので、この式の結果は関数の戻り値になります。そして、この関数は、プロパティを割り当てた後、オブジェクト(渡されたオブジェクト)を返します。

この式は変数cと同等であるため、式の戻り値(関数の戻り値)は変数cで保持されるようになりました。

これらすべてを正しく読むと、変数cがオブジェクトを保持し、そのオブジェクトは、数値1に警告する関数であるプロパティaを持つことになります。また、そのオブジェクトも以前に持っていた可能性のあるプロパティを保持します。

このコードを非醜くして、変数名を説明的にするだけで読みやすくするとします。

_var myObject = (function(someObject) {
    if (someObject === undefined) {
        someObject = {};
    }
    function alertOne () {
        alert(1);
    }
    someObject.alertOne = alertOne;
    return someObject;
}(myObject));
_

このショーは、パターンを明らかにするシリーズモジュールのエピソードであり、グローバルスコープを汚染することなく、以前に宣言されたオブジェクトにエレガントな方法でプロパティを追加する方法を示しています。即時呼び出し関数式(IIFE)の主演。

13
newuser

なぜ最後に(c))を書き直したのですか?

これは 即時呼び出し関数 という名前です。

_(function(received argument){

     //some code here.......

})(passed argument)  //<-- here the function is invoked 
_

cは渡された引数です。関数は、作成されるとすぐに呼び出されます。このタイプの宣言は、変数をプライベートに保ち、グローバル名前空間をクリーンに保つために使用されます。

コード内のパターンは、 modules を作成するために使用されます。

............コードに来てください:............

渡された引数が未定義の場合:.............

まず、...}(c))即時呼び出し関数のこの部分が呼び出されます。これは、まだ定義されていないcという引数とともに渡されます。 _(function(c){..._部分はこのc引数を受け取ります。

ここでは、最初は_passed argument c_が未定義であるため、if(c==undefined)がトリガーされます。この時点で、_c={}_ステートメントを使用して、未定義のオブジェクトcに_empty object_が割り当てられます。

ここで、function a() { //... }は、モジュール内で作成されたprivateメソッドです。グローバルにアクセスできます。

プライベートメソッドaが作成されますグローバルに利用可能_c.a=a_ステートメントを使用してcに割り当てることにより、オブジェクトが返されるときに、グローバルコンテキストでこのメソッドを呼び出すことができます。

したがって、新しく作成された空のオブジェクトcにはaというメソッドが割り当てられ、それが返され、_var c_がこのオブジェクトを受け取ります。

渡された引数が未定義でない場合:............

しかし、_passed c_が_not undefined_の場合、たとえば、オブジェクトが渡された場合、新しいオブジェクトは作成されません。つまり、if(c==undefined)が偽物である場合、実行されません。つまり、新しい空のオブジェクトは作成されません。次に、渡されたオブジェクトには、_c.a=a_を使用してaという新しいメソッドが割り当てられます。

それは簡単です。

以下のコードは、コードのはるかに単純なバージョンです。空のオブジェクトが最初に未定義の場合は自動的に送信されるため、未定義かどうかを確認する手間がかかりません。 loose augmentation。 と呼ばれます。

_var c = (function(c) {

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c || {} ));
_
5
AL-zami

Ben Cherry によって書かれたこの記事は、このタイプのパターンを理解するのに役立ちました: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

記事からの抜粋:

匿名の閉鎖

これは、すべてを可能にする基本的な構成であり、JavaScriptの唯一の最高の機能です。匿名関数を作成し、すぐに実行します。関数内で実行されるすべてのコードはクロージャ内にあり、アプリケーションの存続期間を通じてプライバシーと状態を提供します。

(function () {
    // ... all vars and functions are in this scope only
    // still maintains access to all globals
}());

無名関数の周りの()に注意してください。トークン関数で始まるステートメントは常に関数宣言と見なされるため、これは言語で必要です。 ()を含めると、代わりに関数式が作成されます。

グローバルインポート

JavaScriptには、暗黙のグローバルと呼ばれる機能があります。名前が使用されるときはいつでも、インタープリターはスコープチェーンを逆方向に歩き、その名前のvarステートメントを探します。何も見つからない場合、その変数はグローバルであると見なされます。割り当てで使用されている場合、グローバルがまだ存在していなければ作成されます。これは、匿名クロージャでグローバル変数を使用または作成するのが簡単であることを意味します。残念ながら、特定のファイルでどの変数がグローバルであるかが(人間には)明らかでないため、これによりコードの管理が困難になります。

幸い、匿名関数は簡単な代替手段を提供します。グローバルをパラメーターとして匿名関数に渡すことで、それらをコードにインポートします。これは、暗黙のグローバルよりも明確で高速です。次に例を示します。

(function ($, YAHOO) {
    // now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

モジュールのエクスポート

seグローバルだけでなく、declareグローバルにしたい場合もあります。これは、無名関数の戻り値を使用してエクスポートすることで簡単に実行できます。そうすることで基本的なモジュールパターンが完成するので、完全な例を次に示します。

var MODULE = (function () {
    var my = {},
        privateVariable = 1;

    function privateMethod() {
        // ...
    }

    my.moduleProperty = 1;
    my.moduleMethod = function () {
        // ...
    };

    return my;
}());

MODULEという名前のグローバルモジュールを宣言し、MODULE.moduleMethodという名前のメソッドとMODULE.modulePropertyという名前の変数の2つのパブリックプロパティがあることに注意してください。さらに、無名関数のクロージャを使用してプライベート内部状態を維持します。また、上記で学習したパターンを使用して、必要なグローバルを簡単にインポートできます

4
llernestal

あなたがしているのは、無名関数を宣言し、それをcと呼ばれるパラメーターで呼び出し、それをcとも呼ばれる変数に割り当てることです。これは、非常に混乱します:-)

変数の名前を変更すると、次のようになります。

var result=(function (input_parameter){...} (parameter_used_to_call_my_function));

あなたが尋ねる最後の(c)は、関数を呼び出すためのパラメーターです。より長い構文を使用すると、より簡単に確認できます。

var my_function=function(input_parameter){...};
var result=my_function(result);

また、resultcと呼んでいますが)をパラメーターとして使用してmy_functionを呼び出していることにも注意してください。これは、保存するために作成した変数の名前でもあります。関数の戻り値。 JSは、変数の処理方法に厳密ではないため、これに対応しますが、これはコードを記述するための紛らわしい方法です。変数を宣言し、それが以前に宣言された場合に備えて、変数(その時点では存在しないはずのその名前の変数)をパラメーターとして関数に渡します(そして、少なくとも関数内でその場合を処理します)一貫性があります)。

my_function内で発生するのは、パラメーターに以前の値があったかどうかを確認することです(前の段落で説明したこと)。未定義の場合は、空のオブジェクトに初期化します。次に、関数をinput_parameterに追加して返します。

このタイプのプログラミングに名前があるかどうかはわかりませんが、同じ変数名をさまざまなものに使用するのは良い考えとは思えません:-)

1
eirasf