ビッグバンをリードするJavaScript関数!構文


204

私はいくつかのライブラリーでこの構文を見てきましたが、その利点は何なのかと思っています。(私はクロージャとコードが何をしているかをよく知っていることに注意してください、私は構文上の違いのみを気にしています)

!function(){
  // do stuff
}();

より一般的なの代わりに

(function(){
  // do stuff
})();

匿名関数を呼び出すため。

いくつか疑問があります。まず、トップの例が実際に機能するのを許可しているものは何ですか?このステートメントを構文的に正しくするために、なぜ強打が必要なのですか?私はそれも+うまくいくと言われています、そして代わりにいくつかの他のものと確信しています!

次に、メリットは何ですか?私が知ることができるのは、それが単一のキャラクターを救うということですが、それが多くのアダプターを引き付けるのにこんなに大きな利点であるとは想像できません。他に不足しているメリットはありますか?

私が見ることができる他の唯一の違いは、自己呼び出し関数の戻り値ですが、これらの例の両方で、クロージャーを作成するためにのみ使用されているため、関数の戻り値については特に気にしません。では、最初の構文を使用する理由を誰かに教えてもらえますか?


フレームワークは、縮小版が最適化できない文字をできるだけ多く保存することを好みます。
アレックス2011

最初に頭に浮かぶのは、(function($){...})(jQuery);のようなサンドボックスを作成できることです。
JSテイラー

2
どちらの例でもこれを実現しています。前述のように、私は私が構文の違いで、より興味が、これらの関数が何をしているかを理解する
ブラッド

8
私は、以前のクルーよりも洗練された方法でキュートであることの必要性、義務、要件に起因します。「ああ、それらの括弧付き異教徒、私たちは持っている!!」
Jared Farrish

2
私はこれについてはまったく知りませんでした。!それが実行されていることを強調しているので、私はが好きです。
cdmckay 2011

回答:


97

理想的には、これらすべてを次のように簡単に実行できるはずです。

function(){
  // do stuff
}(); 

つまり、無名関数を宣言して実行します。しかし、JS文法の仕様により、これは機能しません。

したがって、これを達成する最も短い形式は、UnaryExpression(したがってCallExpression)などの式を使用することです。

!function(){
  // do stuff
}(); 

または楽しみのために:

-function(){
  // do stuff
}(); 

または:

+function(){
  // do stuff
}(); 

あるいは:

~function(){
  // do stuff
  return 0;
}( );

3
それで、唯一の利点は簡潔さですか?
ブラッド、

12
私はで性能試験を上記のすべてのオプションを追加しました:jsperf.com/bang-function
Shaz

5
私が言う表現力。このような場合、1回しか実行されないため、速度はそれほど重要ではありません。
c-smile

1
好奇心から、私はバンとバンのどちらも最も速く機能しないことに気づきましたが、少なくともChromeの進化のどこかで、バンはバンなしよりも速くなりました。(おそらく統計的に重要ではないが...)理由はありますか?ボンネットの下のコードについてはあまり知りませんが、とても魅力的です。
jmk2142

セミコロンがない場合、2つの単項演算子はバイナリとして解釈されます。最初と最後がこれらの例の中で最も安全です。

73

Javascriptでは、で始まる行functionは関数ステートメントであることが想定されており、次のようになるはずです。

function doSomething() {
}

のような自己呼び出し機能

function(){
  // do stuff
}();

はそのフォームに適合しません(関数名がないため、最初の開始括弧で構文エラーが発生します)。そのため、括弧は匿名関数式を表すために使用されます

(function(){
  // do stuff
})();

しかし、(関数ステートメントではなく)式を作成するものであれば何でも実行できるため、!。これは、これが関数ステートメントではないことをインタープリターに伝えています。それ以外では、演算子の優先順位により、関数は否定の前に呼び出されることが決まります。

私はこの慣習に気づいていませんでしたが、それが一般的になると読みやすさに貢献するかもしれません。つまり!function、大規模なコードブロックの先頭でを読む人は、自己呼び出しを期待することになります(function。ただし、これらの煩わしい括弧は失われます。速度や文字数の節約とは対照的に、それが理由だと思います。


この「関数で始まる行は期待されています...」はかなりあいまいに見えます。これはどうですか:var foo = {CR/LF here} function bar() {}
c-smile

45

すでに述べられていることの他に、!セミコロンなしでjavascriptを書く場合に便利です:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

最初の例は予想どおり「ham」を出力しますが、次の括弧が原因でi = 2ステートメントが終了しないため、2番目の例はエラーをスローします。

また、連結されたjavascriptファイルでは、前のコードにセミコロンがない場合でも心配する必要はありません。したがって、共通の;(function(){})();は必要ありません。あなた自身が壊れないことを確認するために。

私の答えは少し遅れていることはわかっていますが、まだ言及されていません。


6
ヒントと思い出の+1 ...最近はセミコロンなしでJavaScriptを書くのは好きではありません。
Pablo Grisafi、2012年

4
Twitter BootstrapはすべてセミコロンなしのJSであり、かなり新しいものです(上記のコメントが皮肉であり、見逃した場合は申し訳ありません)。
ブランドワッフル2012

2
これは実際には当てはまりません。次の例について考えてみます。!function(){console.log( "ham");}()!function(){console.log( "cheese")}(); 「SyntaxError:Unexpected token!」というエラーが表示されます。
Heavysixer 2013

はい、そうです。それらを同じ行に置くと、エラーになります。私はそれについて考えていませんでした。しかし、私がこれまでに使用した連結スクリプト/ライブラリはそれを行いません。また、ファイルを縮小して連結すると、ファイルのセミコロンが追加されます。だから、正直なところ、あなたがその問題に遭遇するようなケースは想像できません。一方、ここは午前2時で、私は無知かもしれません:)
スモー

6

1つには、jsPerfは!(UnaryExpressionの)を使用した方が通常は高速であることを示しています。時々、彼らは平等であることが判明しますが、彼らが等しくないとき、私は、きっちりとはめられていない者が他の者よりもあまりにも多くの勝利を収めているのを見たことはありません。 http //jsperf.com/bang-function

これは、最も古い(たとえば、..)Chrome、バージョン8を搭載した最新のUbuntuでテストされています。したがって、結果は当然異なる場合があります。

編集:クレイジーなものはどうdeleteですか?

delete function() {
   alert("Hi!"); 
}();

またはvoid

void function() {
   alert("Hi!"); 
}();

面白い!サファリではスピードに関しては、50対50くらいが得られましたが、強打されていないものは確かにそれを保持していました。潜在的な速度の違いについての理論はあるのでしょうか?
ブラッド、2011

@bradサファリと関係があるはずです。テストを見ると、他のほとんどのブラウザが支持しているようです!。しかし、私もこれに関する理論を見つけたいと思います:)
Shaz

3
空のように私は明示的に「私は、戻り値を気にしない」と言って、それが他の言語の規則のことを思い出すためにしているため
code_monk

4

ここを見るとわかるように、JavaScriptで自己呼び出しメソッドを実行する最良の方法は、次のものを使用することです。

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec

1
パフォーマンスがどちらかの構文を使用する理由であるとは思えません。70M ops / secで、クロージャの宣言はとにかく内部のコードより数千倍速くなります
Eloims

3

したがって、否定「!」+、-、〜、delete、voidなどの他のすべての単項演算子は、要約すると次のようになります。

!function(){
  alert("Hi!");
}(); 

または

void function(){
  alert("Hi!");
}();

または

delete function(){
  alert("Hi!");
}();

そして、楽しみのためにバイナリ演算子を使用するいくつかのケース:)

1 > function() {
   alert("Hi!"); 
}();

または

1 * function() {
   alert("Hi!"); 
}();

または

1 >>> function() {
   alert("Hi!"); 
}();

あるいは

1 == function() {
   alert("Hi!"); 
}();

他の誰かのために三項を残します:)


12
0?0:function() { alert("Hi!"); }();
daniel1426 2014年

ビンゴ、ダン!私たちには三項があります;)
アーマン・マクヒタリアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.