23

JavaScript には 2 つの一般的なクロージャ スタイルがあります。最初に匿名コンストラクターを呼び出します:

new function() { 
  var code...
}

およびインラインで実行される関数:

(function() {
  var code...
})();

これら2つの動作に違いはありますか?一方が他方よりも「優れている」のですか?

4

5 に答える 5

12

どちらの場合も関数を実行します。唯一の違いは、式の戻り値と、関数内の "this" の値です。

基本的には

new expression

実質的に同等です

var tempObject = {};
var result = expression.call(tempObject);
if (result is not an object)
    result = tempObject;

もちろん、 tempObject と result は決して見ることができない一時的な値ですが (それらはインタープリターの実装の詳細です)、「オブジェクトではない」チェックを行う JS メカニズムはありません。

大まかに言えば、「new function() { .. }」メソッドは、コンストラクター用に this オブジェクトを作成する必要があるため、遅くなります。

つまり、オブジェクトの割り当ては遅くないため、これは実際の違いではないはずであり、そのようなコードをホットコードで使用するべきではありません (関数オブジェクトと関連するクロージャーを作成するコストのため)。

編集:これから見逃したことに気付いたのは、tempObjectwill がexpressionプロトタイプを取得することです。(の前expression.call)tempObject.__proto__ = expression.prototype

于 2008-08-08T22:02:14.830 に答える
5

@Lance: 最初のものも実行中です。名前付きコンストラクターと比較します。

function Blah() {
    alert('blah');
}
new Bla();

これは実際にはコードも実行しています。同じことが匿名コンストラクターにも当てはまります...

しかし、それは問題ではありませんでした;-)

于 2008-08-08T21:08:38.197 に答える
3

どちらもコード ブロックを実行してクロージャを作成します。スタイルの問題として、私はいくつかの理由から 2 番目を好みます。

コードが実際に実行されることは、一見しただけではすぐにはわかりません。この行は、コンストラクターとして実行するのではなく、新しい関数を作成しているように見えますが、実際にはそうではありません。実行しているように見えることを実行しないコードは避けてください。

また、クロージャースコープに出入りしていることをすぐに確認できるように、素敵なブックエンドトークンを作成します(function(){})();これは、スコープの変更を読み込んでプログラマーに警告するため、特に便利です。たとえば、縮小など、ファイルの後処理を行う場合に役立ちます。

于 2008-08-09T02:20:29.597 に答える
0

さて、こんなページを作りました。

<html>
<body>
<script type="text/javascript">
var a = new function() { 
  alert("method 1");

  return "test";
};

var b = (function() {
  alert("method 2");

  return "test";
})();

alert(a);  //a is a function
alert(b);  //b is a string containing "test"

</script>
</body>
</html>

驚くべきことに(とにかく私にとって)「メソッド 1」と「メソッド 2」の両方が警告されました。「メソッド 1」が警告されるとは思っていませんでした。違いは、a と b の値が何であるかでした。 b は関数が返す文字列です。

于 2008-08-08T22:20:46.540 に答える
-4

はい、両者には違いがあります。

どちらも匿名関数であり、まったく同じ方法で実行されます。ただし、2 つの違いは、2 番目のケースでは、変数のスコープが無名関数自体に制限されることです。誤って変数をグローバル スコープに追加する可能性はありません。

これは、2 番目の方法を使用することで、グローバル変数のスコープが乱雑にならないことを意味します。これは、これらのグローバル変数の値が、他のライブラリで使用する可能性がある、またはサード パーティのライブラリで使用されている他のグローバル変数に干渉する可能性があるためです。 .

例:

<html>
<body>
<script type="text/javascript">

new function() { 
a = "Hello";
alert(a + " Inside Function");
};

alert(a + " Outside Function");

(function() { 
var b = "World";
alert(b + " Inside Function");
})();

alert(b + " Outside Function");
</script>
</body>
</html>

上記のコードでは、出力は次のようになります。

Hello Inside 関数
Hello Outside 関数
World Inside 関数

...すると、「b」が関数の外で定義されていないため、エラーが発生します!

したがって、2 番目の方法の方が安全だと思います。

于 2008-08-09T00:29:38.633 に答える