web-dev-qa-db-ja.com

JavaScriptでは、(function(){})()よりも!function(){}()の利点は何ですか?

可能性のある複製:
感嘆符は関数の前に何をしますか?

私は長い間、JavaScriptでの自己実行型の匿名関数に以下を使用しています。

(function () { /* magic happens */ })()

最近、次のパターンのインスタンスが増え始めています(例: Bootstrap ):

!function () { /* presumably the same magic happens */ }()

2番目のパターンの利点を知っている人はいますか?または、それは単なる文体の好みですか?

82
Andrew Hedges

これらの2つの異なる手法には、機能の difference と外観の違いがあります。他の方法に対する1つの技術の潜在的な利点は、これらの違いによるものです。

正確さ

JavaScriptは、concisionが非常に重要になる可能性がある言語です。Javascriptは、ページの読み込み時にダウンロードされるため。つまり、Javascriptが簡潔であるほどダウンロード時間が速くなります。このため、Javascriptファイルを圧縮してダウンロード時間を最適化するJavascript minifiers および obfuscators があります。たとえば、alert ( "Hi" ) ;のスペースはalert("Hi");に最適化されます。

これを念頭に置いて、これら2つのパターンを比較してください

  • 通常 closure:_(function(){})()_16文字
  • 否定 クロージャ!function(){}()15文字

これはせいぜいマイクロ最適化であるため、 code golf コンテストを行わない限り、これは特に説得力のある議論ではありません。

戻り値を否定する

abの結果値を比較します。

_var a = (function(){})()
var b = !function(){}()
_

a関数は何も返さないため、aundefinedになります。 undefinedの否定はtrueであるため、btrueと評価されます。これは、関数の戻り値を無効にするか、すべてを返す必要があり、null以外または未定義の値のフェチを持つ必要がある人にとっては利点です。これがこの 他のスタックオーバーフローの質問でどのように機能するかの説明を見ることができます。

これが、通常 アンチパターン と見なされるこの関数宣言の根拠を理解するのに役立つことを願っています。

80
Peter Olson

私はいつもこのような質問には Ben AlmanのIIFEピース を使用します。私に関する限り、それは決定的なものです。

記事 の要点は次のとおりです。

// Either of the following two patterns can be used to immediately invoke
// a function expression, utilizing the function's execution context to
// create "privacy."

(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well

// Because the point of the parens or coercing operators is to disambiguate
// between function expressions and function declarations, they can be
// omitted when the parser already expects an expression (but please see the
// "important note" below).

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// If you don't care about the return value, or the possibility of making
// your code slightly harder to read, you can save a byte by just prefixing
// the function with a unary operator.

!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

// Here's another variation, from @kuvos - I'm not sure of the performance
// implications, if any, of using the `new` keyword, but it works.
// http://Twitter.com/kuvos/status/18209252090847232

new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments
53
Skilldrick

重要なことは、基本的にはパーサーが関数を関数宣言として解釈しないようにすることであり、代わりに匿名関数式として解釈されることです。

括弧を使用して式をグループ化するか、!リターンを無効にすることは、どちらも解析を変更するためのテクニックにすぎません。その後、次の括弧によってすぐに呼び出されます。明示的な戻り値がないと仮定すると、これらのフォームはどれも、その点で同じ正味の効果があります。

(function(){ /* ... */ })(); // Arguably most common form, => undefined
(function(){ /* ... */ }()); // Crockford-approved version, => undefined
!function(){ /* ... */ }();  // Negates the return, so => true
+function(){ /* ... */ }();  // Attempts numeric conversion of undefined, => NaN
~function(){ /* ... */ }();  // Bitwise NOT, => -1

戻り値をキャプチャしない場合、大きな違いはありません。 〜はビットを反転するだけなので、より高速な操作かもしれません、または多分! true/falseチェックであり、否定を返すため、より高速な操作です。

しかし結局のところ、ほとんどの人がこのパターンを使用している方法は、新しいレベルのスコープを打ち切り、物事をきれいに保つことです。どんな仕事でも。後者の形式は一般的ですが、追加の(通常は不要な)操作が導入される一方で、余分なバイトをすべて保存することが役立つためです。

ベンアルマンはこのトピックについて素晴らしい記事を書いています: http://benalman.com/news/2010/11/immediately-invoked-function-expression/

14

最初の「パターン」は匿名関数を呼び出し(その戻り値の結果を持ちます)、2番目の「パターン」は匿名関数を呼び出してその結果を否定します。

それはあなたが求めていることですか? notは同じことを行います。

4
Blindy

!が関数の戻り値を提供する(つまり、!undefinedからのtrueを返す)ことを除いて、これはほぼ唯一のスタイル設定です。

また、1文字少なくなります。

4
doctorless

最初のケースでは、実行するオブジェクトを_( )_の次のセットでラップするために_()_を使用しています。次のケースでは、1つの引数を取る演算子(否定演算子!)を使用しています。そして、その引数(関数)を_( )_で暗黙的にラップするようにして、実際に!(function () { })()を取得し、関数を実行して、返される結果を否定します。これらの演算子はすべて1つの引数を取るため、これは_-, +, ~_でも同じ原理で機能します。

_!function () { /* presumably the same magic happens */ }()
-function () { /* presumably the same magic happens */ }()
+function () { /* presumably the same magic happens */ }()
~function () { /* presumably the same magic happens */ }()
_

なぜこれをしたいのですか?個人的な好みか、大きな.JSがあり、匿名の関数呼び出しごとに1文字を節約したい場合は、次のように思います...:D

1
Cipi