29

GithubでCoffeeScriptのソースコードを確認しているときに、すべてではないにしても、ほとんどのモジュールが次のように定義されていることに気付きました。

(function() {
    ...
}).call(this);

このパターンは、モジュール全体を無名関数でラップし、それ自体を呼び出すように見えます。

このアプローチの長所(および短所)は何ですか?同じ目標を達成する他の方法はありますか?

4

3 に答える 3

78

Harmen の回答は非常に優れていますが、CoffeeScript コンパイラによってこれが行われる場所とその理由について少し詳しく説明させてください。

で何かをコンパイルするとcoffee -c foo.coffee、常にfoo.js次のような が得られます。

(function() {
  ...
}).call(this);

何故ですか?さて、次のような割り当てを入れたとします

x = 'stringy string'

foo.coffee。それを確認すると、コンパイラは次のように尋ねます。xこのスコープまたは外部スコープに既に存在しますか? そうでない場合はvar x、JavaScript 出力のスコープの先頭に宣言を配置します。

今、あなたが書いたとします

x = 42

で、両方をコンパイルし、デプロイのためbar.coffeeに連結foo.jsします。bar.jsあなたは得るでしょう

(function() {
  var x;
  x = 'stringy string';
  ...
}).call(this);
(function() {
  var x;
  x = 42;
  ...
}).call(this);

そのため、xインfoo.coffeexインbar.coffeeは互いに完全に分離されています。これは CoffeeScript の重要な部分です。変数は、明示的にエクスポートされない限り(共有グローバルにアタッチするか、Node.js で) 、ある .coffee ファイルから別の .coffee ファイルにリークすることはありません。exports

-b("bare") フラグを使用してこれをオーバーライドできますcoffeeが、これは非常に特殊な場合にのみ使用する必要があります。上記の例で使用すると、得られる出力は次のようになります。

var x;
x = 'stringy string';
...
var x;
x = 42;
...

これは悲惨な結果をもたらす可能性があります。これを自分でテストするには、 を追加setTimeout (-> alert x), 1してみてくださいfoo.coffee。また、2 つの JS ファイルを自分で連結する必要はないことに注意してください。2 つの個別の<script>タグを使用してそれらをページに含めた場合でも、それらは効果的に 1 つのファイルとして実行されます。

さまざまなモジュールのスコープを分離することにより、CoffeeScript コンパイラは、プロジェクト内のさまざまなファイルが同じローカル変数名を使用する可能性があるかどうかを心配するという頭痛から解放されます。これは、JavaScript の世界では一般的な方法です (たとえば、jQuery ソースや、ほぼすべての jQuery プラグインを参照してください)。CoffeeScript が自動的に処理します。

于 2011-03-06T18:19:56.670 に答える
19

このアプローチの良い点は、プライベート変数が作成されるため、変数名と競合しないことです。

(function() {
  var privateVar = 'test';
  alert(privateVar); // test
})();

alert(typeof privateVar); // undefined

を追加.call(this)すると、thisキーワードは関数の外で参照されるのと同じ値を参照します。追加されていない場合、thisキーワードは自動的にグローバル オブジェクトを参照します。

違いを示す簡単な例を次に示します。

function coffee(){
  this.val = 'test';
  this.module = (function(){
    return this.val;
  }).call(this);
}

var instance = new coffee();
alert(instance.module); // test

function coffee(){
  this.val = 'test';
  this.module = (function(){
    return this.val;
  })();
}

var instance = new coffee();
alert(typeof instance.module); // undefined
于 2011-03-06T16:20:31.207 に答える
1

これは次のような構文です。

(function() {

}());

これを即時関数と呼びます。関数が定義され、すぐに実行されます。これの長所は、すべてのコードをこのブロック内に配置し、関数を単一のグローバル変数に割り当てることができるため、グローバル名前空間の汚染を減らすことができることです。関数内に適切なスコープを提供します。

これは、モジュールを作成するときに使用する典型的なパターンです。

var MY_MODULE = (function() {
    //local variables
    var variable1,
        variable2,
        _self = {},
        etc

    // public API
    _self = {
       someMethod: function () {

       }
    }

    return _self;
}());

短所が正確に何であるかはわかりません。他の誰かが何かを知っていれば、喜んでそれらについて学びます.

于 2011-03-06T16:20:36.870 に答える