8

DailyJSの「JavaScript フレームワークを作ろう」から、次のコードについてはよくわかりませんが、明らかにグローバルな削減手法として使用されています。

これまでの私の理解は (function(){}) に行き詰まります。turing var を設定し、global.turing を turing に設定し、window または this (ブラウザーにない場合) を返すことは理解していますが、(function(global){})(this または window) のことは私を混乱させます...私は次のようなものを見てきました

var mything = {}神話の下にすべてのコードを設定しますが、このイディオムは私を少し混乱させます.

ここでの理由と、それが「うまくいく」ことを暗記することを本当に理解したい

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);
4

2 に答える 2

10

(この回答は4年以上前のものです(2015年4月現在)。まだ正しいですが、より一般的な説明が必要だと思います-以下を参照してください)

元の答え

これについて考えてください:

(function (x) {
    // ...
})(y);

なので:

function functionName(x) {
    // ...
}
functionName(y);

ただし、名前を付ける必要はありません (functionName など)。

したがって、この:

(function(global) {
    // ...
})(typeof window === 'undefined' ? this : window);

本当にただ:

function functionName(global) {
    // ...
}
functionName(typeof window === 'undefined' ? this : window);

これは 1 つの引数 (global関数内で呼び出される) を持つ関数でありtypeof window === 'undefined' ? this : window、以下と同じ意味で呼び出されます。

function functionName(global) {
    // ...
}
if (typeof window === 'undefined') {
    functionName(this);
} else {
    functionName(window);
}

ただし、短い表記を使用します (関数に名前を付けずに)。

より一般的な説明

私はこの回答を 4 年以上前に書きましたが、ここに含まれる概念の一般的な説明を追加する時が来たと思います。

上で説明したように、これは次のとおりです。

(function (x) {
    // ...
})(y);

これの匿名バージョンです:

function functionName(x) {
    // ...
}
functionName(y);

これは(一度だけ呼び出す場合)通常(例外については以下を参照)、これと同じです:

function functionName() {
    var x = y;
    // ...
}
functionName();

匿名の即時呼び出し関数に戻ると、次のようになります。

(function (x) {
    // ...
})(y);

これと同じです:

(function () {
    var x = y;
    // ...
})();

これは、ほとんどの人にとってより明白な意味を持つ可能性があります。(ここで、すぐに呼び出される関数には引数がなく、変数やその他のネストされた関数に分離されたスコープを提供する目的のみに役立ちます。これにより、外側またはグローバル スコープを汚染しません。これは、引数を使用する主な理由でもあります。最初に無名関数をすぐに呼び出します。)

括弧について

ちなみにこれ:

(function () {
    // ...
})();

これと同じです:

(function () {
    // ...
}());

言語のあいまいさのために関数を囲む括弧が必要ですが、()関数を実際に呼び出す が含まれている場合と含まれていない場合があります。詳細と、最初のバージョンが「犬のボール」のように見えると彼が考える理由については、Douglas Crockford によるこの説明を参照してください。

例外

以前、私はこう言いました。

(function (x) {
    // ...
}(y));

これと同じです:

(function () {
    var x = y;
    // ...
}());

そして、これはほとんどの場合、1 つの引数に当てはまり (同時にその値に依存している間、外側のスコープで同じ名前の変数をマスクしません)、通常は複数の引数に当てはまります (そうでない場合)。 t も相互に依存します)。例でより明確になることを願っています。

このコードがある場合:

(function (x) {
    // ...
}(x + 1));

次に、それを次のように翻訳することはできません。

(function () {
    var x = x + 1;
    // ...
}());

最初のバージョンでは、外部 に 1 を追加し、結果を内部xにバインドし、関数の内部に入るとすぐに、内部のみを操作する必要があるためです(新しいステートメントでさえ、それには役立ちません)。 xxlet

もう一つの例:

(function (x, outer_x) {
    // ...
}(1, x));

ここでは、外側のスコープと内側のスコープの値を 1 の新しい値に設定できold_xx順序xを気にする必要はありません。しかし、あなたがした場合:

概要

ご覧のとおり、単純に翻訳できない状況がいくつかあります。

(function (x) {
    // ...
}(y));

の中へ:

(function () {
    var x = y;
    // ...
}());

しかし、それが 2 番目の形式に翻訳できるのであれば、それは読みやすさのためであるべきだと私は主張します。特に大きな関数の場合、関数の先頭で使用されている変数の意味を知るために、関数の最後までスクロールする必要があるのは不便です。

質問に戻る

つまり、このコードを質問から翻訳します。

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

これに:

(function () {
  var global = typeof window === 'undefined' ? this : window;
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
}());

この回答で、これら2つが同等である理由が説明され、次のように記述できることを願っています。

(function (global, turing) {
  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window,
   {VERSION: '0.0.1', lesson: 'Part 1: Library Architecture'});

それは同じことを意味しますが、同時に読みにくくなります。

同様の概念を説明している他の回答も参照してください。

于 2011-03-15T22:41:49.863 に答える
1

これは匿名関数またはラムダ関数です。ほとんどの言語がこれをサポートしています。

無名関数の使用は、作成者の好みの問題です。以前の呼び出しの戻り値を処理する匿名関数を設定しないと、変数を初期化して返されたオブジェクトを格納し、後でグローバルに宣言された関数に渡すことによって、クライアント側で追加のメモリを割り当てる必要があります。シリアル方式。

1回限りの機能であれば、スペース、メモリ、時間を節約できます。

補足として、関数型プログラミングの背後にあるいくつかの概念についてグーグルで検索することで、おそらくこれについてより良い感覚を得ることができます。Lambda 関数は最近、特に Python で大流行しているようです。

于 2011-03-15T22:46:06.863 に答える