近況:最近一直忙着找實習沒有更新,不過學習還是在繼續的。最近在寫Node.js又稍帶把javascript的角落知識撿了一遍,過半個月打算去看看python和一些CSS深層的書和博客。工作找的還好,拿了兩份實習offer,決定好去當小二了。這幾天在看司徒老師的《javascript框架設計》,開篇第一張講種子模塊(即核心模塊)里面提到了一個沒見過的縮寫詞IIFE,查了查、看了看。
1.什么是IIFE
IIFE是縮寫,全拼Imdiately Invoked Function Expression,立即執行的函數表達式。
這時候可能就容易想起了這種語法:
(function(){ //...... })();
就是我們平時常寫的匿名函數的立即執行語句。
IIFE就是這個,但是不止如此,還有另外的幾種語句格式:+,-,~,!,void。
+function(){ //code 1 }(); -function(){ //code 2 }(); !function(){ //code 3 }(); ~function(){ //code 4 }(); void function(){ //code 5 }(); (function(){ //code 6 })();
上面幾個函數雖然格式不同,但是作用是一樣的:使匿名函數立即執行。
其中最后一種(function(){//...})(),之前在學js,當時有本書里稱()為強制運算符。其實不是,js沒有強制運算符這個概念,第一對括號()即包裹在function外部的作用實際是給js解釋器||引擎提供一種解析方案,提示解釋器該括號內部包括的是一整體內容。第二個括號的作用是函數調用執行,但是如果直接通過function(){//....}()或者function A(){//...}();是不能執行的,因為引擎默認在遇到function(){}結構時會認為是函數聲明,最后面的()會被單獨解析,然后就語法報錯了。
同理前幾種IIFE語句也是通過一元操作符+-~!變成了函數表達式,目的是為了提示js解析器,告訴js解釋器該運算符附近是一個表達式。
function A(){ //... }(); //上面的寫法被解析時等價於 function A(){ }; (); //報錯
IIFE方式和正常的先聲明再調用相比較,有如下的特點:
1.實現立即執行,不需要先聲明再調用。
2.匿名函數自身不污染全局環境,同時為內部變量提供作用於環境空間。(現在主流的框架都是用這個方式來初始化命名空間的)
3.縮寫形參有利於內部代碼的壓縮
4.提供閉包環境,可以做閉包想做的事情
(function(w,$){ //內部再次調用window對象和jQuery對象時,可直接使用w和$訪問 })(window,jQuery);
同時通過傳入全局對象也能使得作用域鏈上變量的查找變快一點。
但是這種方式存在一個“算不上問題”的問題,見過網上提出說這種方式會造成代碼可讀性差
雖然這種執行方式看上去很簡單,卻是幾乎所有框架的種子模塊的執行函數。(種子模塊是框架中最先執行的部分,從功能來講也是這個框架能夠被使用的核心模塊。種子模塊的主要作用是創建命名空間、搭建基對象、提供函數拓展、事件綁定、沖突處理等等。IIFE就是框架自執行的“init函數”了。)
2.IIFE幾種語句形式的區別
沒啥區別,但是之前看到博客里面有人對這個做了下性能對比。找到了測試的原網站http://jsperf.com/iife-different-operator-efficiency,跑了一下,結果如圖。

本機是mac,用的chrome41瀏覽器。void格式效果最好,和最差的+直接差了20%。+已經很高效了,所以我覺得沒必要在意那一點差別,畢竟很少需要千萬次調用IIFE格式的函數。后來又跑了一次,發現數值是在微動變化的。所以具體使用哪種就看習慣了。
下面是一些主流框架使用的格式:
jQuery1.10 (function(){//...})(window);
Bootstrap3 +(function(a){"use strict";//...})(jQuery);
AmazeUI !(function(){//...})
Zepto (function(){//...})();
IIFE就能寫出來這么多,沒太多干貨,隨手記個熱鬧。
