【JavaScript基礎筆記】模塊化、立即執行函數應用、閉包應用
模塊化:為了提高JS代碼的長期可讀性,易維護性,將JS代碼根據其對應的功能塊區分成不同的JS文件,並將其包裹在立即執行函數內,從而使其中的變量設定為局部變量,不會造成不同模塊的變量汙染。
立即執行函數
在 Javascript 中,圓括號()是一種運算符,跟在函數名之後,表示調用該函數。比如,print()就表示調用print函數。
有時,我們需要在定義函數之後,立即調用該函數。這時,你不能在函數的定義之後加上圓括號,這會產生語法錯誤。
產生這個錯誤的原因是,function這個關鍵字即可以當作語句,也可以當作表達式。
為了避免解析上的歧義,JavaScript 引擎規定,如果function關鍵字出現在行首,一律解釋成語句。因此,JavaScript引擎看到行首是function關鍵字之後,認為這一段都是函數的定義,不應該以圓括號結尾,所以就報錯了。
解決方法就是不要讓function出現在行首,讓引擎將其理解成一個表達式。最簡單的處理,就是將其放在一個圓括號裏面。
上面兩種寫法都是以圓括號開頭,引擎就會認為後面跟的是一個表示式,而不是函數定義語句,所以就避免了錯誤。這就叫做“立即調用的函數表達式”(Immediately-Invoked Function Expression),簡稱 IIFE。
註意,上面兩種寫法最後的分號都是必須的。如果省略分號,遇到連著兩個 IIFE,可能就會報錯。
推而廣之,任何讓解釋器以表達式來處理函數定義的方法,都能產生同樣的效果,比如下面三種寫法。
甚至像下面這樣寫,也是可以的。
通常情況下,只對匿名函數使用這種“立即執行的函數表達式”。它的目的有兩個:一是不必為函數命名,避免了汙染全局變量;二是 IIFE 內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。
如何使用立即執行函數
ES 5 裏面,只有函數有局部變量,於是我們聲明一個 function xxx,然後 xxx.call() 這個時候 xxx 是全局變量(全局函數)。
所以我們不能給這個函數名字 function(){}.call() 但是 Chrome 報錯,語法錯誤。
經過嘗試得到幾種方法可以不報錯:
- !function(){}.call() 【我們不在乎這個匿名函數的返回值,所以加個 ! 取反沒關系】
- (function(){}).call() xxx (function(){}).call() 【如果(fn).call前誤寫xxx,會導致意外函數執行,不推薦】
- frank192837192463981273912873098127912378.call() 【冗長繁雜,不推薦】
閉包的應用
當我們通過模塊化我們的JS代碼文件後,立即執行函數使得我們的模塊文件無法被外部訪問。
那麽,如果遇到A模塊需要引用B模塊的變量時,我們可以通過將xxx變量添加到window的屬性下,然後在另一個模塊中也同樣將window.xxx的地址賦值給xxx,這樣就可實現模塊數據溝通。
如果需要隱藏數據的細節,實現訪問控制,那麽我們還可以通過閉包,使得B模塊可以操作由A模塊裏的變量構造的函數,但無法訪問A模塊裏的變量數據
!function(){ var dinner = { main: noodle; guests : 2 } window.guestsIncrease = function(){ numeber += 1 return number } }.call()
當然我們也可以不使用window全局變量,通過自己設置的局部變量實現。本質上都是一樣的將這個匿名函數的引用通過閉包保存起來,然後立即執行。
var accessor = function(){ var dinner = { main: noodle; guests : 2 } return function(){ numeber += 1 return number } } // B模塊 var increase = accessor.call() increase.call()
【JavaScript基礎筆記】模塊化、立即執行函數應用、閉包應用