86

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

私は長い間、JavaScript の自己実行型の無名関数に次の関数を使用してきました。

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

最近、次のパターンのインスタンスをより多く見始めました (例: Bootstrap内):

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

2番目のパターンの利点を知っている人はいますか? それとも、単にスタイル上の好みですか?

4

6 に答える 6

82

これらの 2 つの異なる手法には、機能的な違いだけでなく、外観の違いもあります。ある手法が他の手法より優れている可能性があるのは、これらの違いによるものです。

簡潔

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

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

  • ノーマルクローズ:   (function(){})() 16文字
  • 否定閉鎖:!function(){}() 15 文字

これはせいぜいマイクロ最適化であるため、コード ゴルフコンテストを行う場合を除き、これは特に説得力のある議論ではないと思います。

戻り値の否定

と の結果値を比較しaますb

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

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

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

于 2011-09-28T17:11:47.833 に答える
53

このような質問については、常に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
于 2011-09-28T17:19:27.097 に答える
14

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

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

(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

戻り値をキャプチャしていない場合、大きな違いはありません。~ はビットを反転するだけなので、より高速な操作である可能性があると主張することができます。真/偽のチェックと否定を返すため、より高速な操作です。

結局のところ、ほとんどの人がこのパターンを使用する方法は、物事をクリーンに保つために新しいレベルの範囲を壊そうとすることです。ありとあらゆる仕事。後者の形式は、追加の (通常は不要な) 操作を導入しますが、すべての余分なバイトを保存すると役立つため、人気があります。

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

于 2011-09-28T17:21:14.060 に答える
4

関数 return を提供するという事実 (つまり、 から来るreturn )を除いて、それはほとんど文体上の好みにすぎません。!true!undefined

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

于 2011-09-28T17:10:20.633 に答える
4

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

それはあなたが求めているものですか?彼らは同じことをしません

于 2011-09-28T17:07:14.600 に答える
1

最初のケースでは、( )実行したいオブジェクトを次の のセットでラップするために使用しています。()次のケースでは、引数を 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

于 2011-09-28T17:20:58.373 に答える