JavaScript には 2 つの一般的なクロージャ スタイルがあります。最初に匿名コンストラクターを呼び出します:
new function() {
var code...
}
およびインラインで実行される関数:
(function() {
var code...
})();
これら2つの動作に違いはありますか?一方が他方よりも「優れている」のですか?
JavaScript には 2 つの一般的なクロージャ スタイルがあります。最初に匿名コンストラクターを呼び出します:
new function() {
var code...
}
およびインラインで実行される関数:
(function() {
var code...
})();
これら2つの動作に違いはありますか?一方が他方よりも「優れている」のですか?
どちらの場合も関数を実行します。唯一の違いは、式の戻り値と、関数内の "this" の値です。
基本的には
new expression
実質的に同等です
var tempObject = {};
var result = expression.call(tempObject);
if (result is not an object)
result = tempObject;
もちろん、 tempObject と result は決して見ることができない一時的な値ですが (それらはインタープリターの実装の詳細です)、「オブジェクトではない」チェックを行う JS メカニズムはありません。
大まかに言えば、「new function() { .. }」メソッドは、コンストラクター用に this オブジェクトを作成する必要があるため、遅くなります。
つまり、オブジェクトの割り当ては遅くないため、これは実際の違いではないはずであり、そのようなコードをホットコードで使用するべきではありません (関数オブジェクトと関連するクロージャーを作成するコストのため)。
編集:これから見逃したことに気付いたのは、tempObject
will がexpression
プロトタイプを取得することです。(の前expression.call
)tempObject.__proto__ = expression.prototype
@Lance: 最初のものも実行中です。名前付きコンストラクターと比較します。
function Blah() {
alert('blah');
}
new Bla();
これは実際にはコードも実行しています。同じことが匿名コンストラクターにも当てはまります...
しかし、それは問題ではありませんでした;-)
どちらもコード ブロックを実行してクロージャを作成します。スタイルの問題として、私はいくつかの理由から 2 番目を好みます。
コードが実際に実行されることは、一見しただけではすぐにはわかりません。この行は、コンストラクターとして実行するのではなく、新しい関数を作成しているように見えますが、実際にはそうではありません。実行しているように見えることを実行しないコードは避けてください。
また、クロージャースコープに出入りしていることをすぐに確認できるように、素敵なブックエンドトークンを作成します(function(){
。})();
これは、スコープの変更を読み込んでプログラマーに警告するため、特に便利です。たとえば、縮小など、ファイルの後処理を行う場合に役立ちます。
さて、こんなページを作りました。
<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 は関数が返す文字列です。
はい、両者には違いがあります。
どちらも匿名関数であり、まったく同じ方法で実行されます。ただし、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 番目の方法の方が安全だと思います。