自執行匿名函數:
常見格式:(function() { /* code */ })();
解釋:包圍函數(function(){})的第一對括號向腳本返回未命名的函數,隨后一對空括號立即執行返回的未命名函數,括號內為匿名函數的參數。
作用:可以用它創建命名空間,只要把自己所有的代碼都寫在這個特殊的函數包裝內,那么外部就不能訪問,除非你允許(變量前加上window,這樣該函數或變量就成為全局)。各JavaScript庫的代碼也基本是這種組織形式。
總結一下,執行函數的作用主要為 匿名 和 自動執行,代碼在被解釋時就已經在運行了。
其他寫法
(function () { /* code */ } ());
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
function與感嘆號
最近有空可以讓我靜下心來看看各種代碼,function與感嘆號的頻繁出現,讓我回想起2個月前我回杭州最后參加團隊會議的時候,@西子劍影拋出的一樣的問題:如果在function之前加上感嘆號 (!) 會怎么樣?比如下面的代碼:
!function(){alert('iifksp')}() // true
在控制台運行后得到的值時true,為什么是true這很容易理解,因為這個匿名函數沒有返回值,默認返回的就是undefined,求反的結果很自然的就是true。所以問題並不在於結果值,而是在於,為什么求反操作能夠讓一個匿名函數的自調變的合法?
平時我們可能對添加括號來調用匿名函數的方式更為習慣:
(function(){alert('iifksp')})() // true
或者:
(function(){alert('iifksp')}()) // true
雖然上述兩者括號的位置不同,不過效果完全一樣。
那么,是什么好處使得為數不少的人對這種嘆號的方式情有獨鍾?如果只是為了節約一個字符未免太沒有必要了,這樣算來即使一個100K的庫恐怕也節省不了多少空間。既然不是空間,那么就是說也許還有時間上的考量,事實很難說清,文章的最后有提到性能。
回到核心問題,為什么能這么做?甚至更為核心的問題是,為什么必須這么做?
其實無論是括號,還是感嘆號,讓整個語句合法做的事情只有一件,就是讓一個函數聲明語句變成了一個表達式。
function a(){alert('iifksp')} // undefined
這是一個函數聲明,如果在這么一個聲明后直接加上括號調用,解析器自然不會理解而報錯:
function a(){alert('iifksp')}() // SyntaxError: unexpected_token
因為這樣的代碼混淆了函數聲明和函數調用,以這種方式聲明的函數 a,就應該以 a(); 的方式調用。
但是括號則不同,它將一個函數聲明轉化成了一個表達式,解析器不再以函數聲明的方式處理函數a,而是作為一個函數表達式處理,也因此只有在程序執行到函數a時它才能被訪問。
所以,任何消除函數聲明和函數表達式間歧義的方法,都可以被解析器正確識別。比如:
var i = function(){return 10}(); // undefined 1 && function(){return true}(); // true 1, function(){alert('iifksp')}(); // undefined
賦值,邏輯,甚至是逗號,各種操作符都可以告訴解析器,這個不是函數聲明,它是個函數表達式。並且,對函數一元運算可以算的上是消除歧義最快的方式,感嘆號只是其中之一,如果不在乎返回值,這些一元運算都是有效的:
!function(){alert('iifksp')}() // true
+function(){alert('iifksp')}() // NaN
-function(){alert('iifksp')}() // NaN
~function(){alert('iifksp')}() // -1
甚至下面這些關鍵字,都能很好的工作:
void function(){alert('iifksp')}() // undefined new function(){alert('iifksp')}() // Object delete function(){alert('iifksp')}() // true
最后,括號做的事情也是一樣的,消除歧義才是它真正的工作,而不是把函數作為一個整體,所以無論括號括在聲明上還是把整個函數都括在里面,都是合法的:
(function(){alert('iifksp')})() // undefined
(function(){alert('iifksp')}()) // undefined
說了這么多,實則在說的一些都是最為基礎的概念——語句,表達式,表達式語句,這些概念如同指針與指針變量一樣容易產生混淆。雖然這種混淆對編程無表征影響,但卻是一塊絆腳石隨時可能因為它而頭破血流。
最后討論下性能。我在jsperf上簡單建立了一個測試:http://jsperf.com/js-funcion-expression-speed ,可以用不同瀏覽器訪問,運行測試查看結果。我也同時將結果羅列如下表所示(由於我比較窮,測試配置有點丟人不過那也沒辦法:奔騰雙核1.4G,2G內存,win7企業版):

可見不同的方式產生的結果並不相同,而且,差別很大,因瀏覽器而異。
但我們還是可以從中找出很多共性:new方法永遠最慢——這也是理所當然的。其它方面很多差距其實不大,但有一點可以肯定的是,感嘆號並非最為理想的選擇。反觀傳統的括號,在測試里表現始終很快,在大多數情況下比感嘆號更快——所以平時我們常用的方式毫無問題,甚至可以說是最優的。加減號在chrome表現驚人,而且在其他瀏覽器下也普遍很快,相比感嘆號效果更好。
當然這只是個簡單測試,不能說明問題。但有些結論是有意義的:括號和加減號最優。
但是為什么這么多開發者鍾情於感嘆號?我覺得這只是一個習慣問題,它們之間的優劣完全可以忽略。一旦習慣了一種代碼風格,那么這種約定會使得程序從混亂變得可讀。如果習慣了感嘆號,我不得不承認,它比括號有更好的可讀性。我不用在閱讀時留意括號的匹配,也不用在編寫時粗心遺忘——
當我也這么干然后嚷嚷着這居然又節省了一個字符而沾沾自喜的時候,卻忘了自己倉皇翻出一本卷邊的C語言教科書的窘迫和荒唐......任何人都有忘記的時候,當再撿起來的時候,撿起的就已經不單單是忘掉的東西了。
2011-10-31更新:如果你使用aptana,那么在使用(!+-)時要注意一點,它們會讓aptana的解析失效,導致Outline窗口沒有任何顯示。但是就代碼本身而言,其運行沒有任何問題。
轉載:https://blog.csdn.net/h330531987/article/details/66275224
JS中關於(function( window, undefined ) {})(window)寫法的理解
在jquery中我們經常看到以下這段代碼:
;(function ( $, window, document, undefined ){
//函數體內具體代碼
})(jQuery, window,document);
首先說說非常值得提倡的幾點:
1、代碼最前面的分號,可以防止多個文件壓縮合並以為其他文件最后一行語句沒加分號,而引起合並后的語法錯誤。
2、匿名函數(function(){})();:由於Javascript執行表達式是從圓括號里面到外面,所以可以用圓括號強制執行聲明的函數。避免函數體內和外部的變量沖突。
3、$實參:$是jquery的簡寫,很多方法和類庫也使用$,這里$接受jQuery對象,也是為了避免$變量沖突,保證插件可以正常運行。
4、window, document實參分別接受window, document對象,window, document對象都是全局環境下的,而在函數體內的window, document其實是局部變量,不是全局的window, document對象。這樣做有個好處就是可以提高性能,減少作用域鏈的查詢時間,如果你在函數體內需要多次調用window 或 document對象,這樣把window 或 document對象當作參數傳進去,這樣做是非常有必要的。當然你如果你的插件用不到這兩個對象,那么就不用傳遞這兩個參數了。
5、最后剩下一個undefined形參了,那么這個形參是干什么用的呢,看起來是有點多余。undefined在老一輩的瀏覽器是不被支持的,直接使用會報錯,js框架要考慮到兼容性,因此增加一個形參undefined
————————————————
版權聲明:本文為CSDN博主「寶哥-NO1」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/code52/article/details/8931786
