javascript模塊化編程-詳解立即執行函數表達式IIFE

一、IIFE解釋

全拼Imdiately Invoked Function Expression,立即執行的函數表達式。

像如下的代碼所示,就是一個匿名立即執行函數:

(function(window, undefined){
  // 代碼...  
})(window);

二、括號的意義

2.1 包住function(){}的括號的意義

這個括號的目的,是為了把function(){}轉化為表達式。像一些庫的源碼,喜歡用如下方式代替:

~function(){
  // 代碼...
}();

或者這種方式:

+function(){
  // 代碼...
}();

其實,作用都一樣,都是把function(){}轉化成一個可執行的表達式,方便執行。
?如果去掉該括號,則會報錯。因為單純的function(){}不是可執行的表達式,會直接報錯。如下圖:

2.1 第二個括號的意義

理解了第一個括號的意義,第二個括號就很簡單了,就是執行表達式了。

三、參數的意義

以這段代碼為例子,講解參數

var wall = {};
(function(window, WALL, undefined){
    
})(window, wall);

參數分為形參和實參。
?function(window, WALL, undefined)三個參數為形參,第二個括號(window, wall)的兩個參數為實參。
?也即可以理解為 window == window,wall == WALL

2.1 普通形參

普通形參是指由windowwall這樣的實際變量傳入指定,可以為任何類型的變量。一個形參就對應一個實參

2.2 特殊形參undefined

為什么形參要多寫一個undefined,這是一個很有趣的話題。
?可以知道這個示例,實參只有兩個,而形參有三個。所以在函數執行的時候,形參undefined會默認賦值為undefined。

形參undefined的作用如下:

2.2.1 防止特殊值undefined被惡意代碼篡改。
?IE6等低版本瀏覽器,undefined是支持被修改的。而這個特殊值被修改后,像以下這種判斷就失效了。

if(wall == undefined){
  // 代碼...
}

所以,這里多加一個形參的目的就是為了防止這種情況發生。只要在這個IIFE作用域內,undefined就能夠正常獲取到。

2.2.2 壓縮代碼可以壓縮undefined
?因為undefined作為形參,像YUI compressor這種類型的代碼壓縮工具,可以將其相關的值進行壓縮,減小文件的體積。

四、寫法解析

4.1 普通寫法

var wall = {}; // 聲明定義一個命名空間wall

// 定義方法
(function(window, WALL, undefined){
    // 給wall命名空間綁定方法say
    WALL.say = function(){
        console.log('hello');
    };
})(window, wall);

(function(window, WALL, undefined){
    // 給wall命名空間綁定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    };
})(window, wall);

// 調用
wall.say();
wall.whoIam();

先定義一個命名空間,然后再給這個命名空間加東西。這是最普遍的寫法,也是最好理解的。
?不足的地方就是必須先聲明一個命名空間,然后才能執行相關的綁定代碼。存在順序加載的問題。

4.2 放大模式

var wall = (function(window, WALL, undefined){
    if(typeof WALL == 'undefined'){
        WALL = {};
    }

    // 給wall命名空間綁定方法say
    WALL.say = function(){
        console.log('hello');
    }

    return WALL; // 返回引用
})(window, wall);

var wall = (function(window, WALL, undefined){
    if(typeof WALL == 'undefined'){
        WALL = {};
    }

    // 給wall命名空間綁定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    }

    return WALL; // 返回引用
})(window, wall);

// 調用
wall.say();
wall.whoIam();

放大模式的好處就是,可以不用考慮代碼加載的先后順序。
?因為js允許wall變量進行重復var聲明,所以這段代碼是可以執行的。
?我可以把IIFE函數拆分成多個文件進行加載,而不會出現普通寫法需要注意的問題。

需要注意的點
?1.IIFE的頭部,都要先進行檢查命名空間是否已經實例化,如果還沒實例化,則進行實例化。
?2.IIFE的尾部,都要return命名空間的引用,使后續代碼能夠得到最新的wall命名空間內容。

4.3 寬放大模式

(function(window, WALL, undefined){
    // 給wall命名空間綁定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

(function(window, WALL, undefined){
    // 給wall命名空間綁定方法 whoIam
    WALL.whoIam = function(){
        console.log('wall');
    }
})(window, window.wall || (window.wall = {}));

// 調用
wall.say();
wall.whoIam();

寬放大模式的重點注意的地方:就是在實參部分的window.wall || (window.wall = {})
?用||運算符進行取巧。
?如果window.wall是已經實例化的,非not defined。則直接返回window.wall的引用,賦值給形參WALL。不會執行||運算符后面的內容。
?如果window.wall還未實例化,則進行實例化。這里要注意的點是實例化是一個賦值操作,需要用括號包起來,變成表達式去執行,才不會報錯。
?表達式(window.wall = {})執行完畢后,會返回新對象window.wall的引用。

寬放大模式的好處:是可以切割成多個文件進行加載,而不必考慮文件加載的先后順序,不存在強耦合關系。
?當然,如果IIFE里面的方法互相引用,還是存在加載依賴的問題。這個問題可以用加載器Require.js等工具解決,這里就不討論了。

五、分文件加載IIFE要注意的點

;(function(window, WALL, undefined){
    // 給wall命名空間綁定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

眼尖的已經看出區別了,就是文件開始的地方,先寫上分號;。
?這樣,多個文件合并的時候,才不會出現收尾相接,代碼出現錯亂的問題。比如下面這種情況:

// a.js 文件
wall.log()

// b.js 文件
(function(window, WALL, undefined){
    // 給wall命名空間綁定方法say
    WALL.say = function(){
        console.log('hello');
    }
})(window, window.wall || (window.wall = {}));

由于a.js文件的wall.log()少寫了分號,跟b.js文件合并后,js就會認為‘wall.log()(...)’是需要這么執行的,結果代碼就報錯了。


覺得不錯的,可以關注模塊化這個系列的文章,容我后續碼字,敬請期待!


喜歡我文章的朋友,掃描以下二維碼,關注我的個人技術博客,我的技術文章會第一時間在博客上更新

點擊鏈接wall的個人博客

wall的個人博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容