2016年5月16日 星期一

[筆記] 為什麼我們要用IIFEs(Immediately Invoked Functions Expressions)


在上一篇文章中,我們提到IIFEs這個概念,並且提到很多的framework都會用這樣的方式來撰寫程式,但是為什麼我們會需要使用IIFEs這種方式來建立函式呢?

如同我們先前在[筆記] JavaScript中的物件做為namespace的簡單運用提到的,namespace的用法可以避免變項名稱重覆所造成的問題,而IIFEs也很類似,它可以避免我們所建立的變項名稱因為覆蓋而造成影響。那麼為什麼可以這樣呢?讓我們繼續瞭解下去。

IIFEs範例


讓我們先回到上堂課[筆記] 談談JavaScript中的IIFEs(Immediately Invoked Functions Expressions)中最後所寫的IIFEs:


讓我們快速的解釋一下這段程式,如果還是不清楚的,可以回去參考一下上一篇文章

為了方便說明,我們把程式碼換行拆開來看一下,首先我們先建立一個匿名函式


要在建立函式後直接執行該函式的方法,就是在該函式後面透過括號 ( ) 直接執行。


最後,因為我們的程式碼是以function開頭,一般來說這是function statement的寫法,可是function statement不能接匿名函式,所以我們要告訴它,我們這其實是一個function expression而不是function statement。要達到這個目的的方式,就是在函式的最外面,加上括號。


IIFEs執行過程解析


讓我們看看,當我們在執行這段程式碼的過程中,JavaScript引擎實際發生了什麼事吧!

首先,當我執行這段程式的時候,程式會先建立Global Execution Context,但是這時候這個Execution Context裡面是沒有任何內容的,因為我們並沒有在Global這層建立任何變項(如果有的話,變項的名稱會先hoisted在Global Execution Context中。)



接著,JavaScript引擎會執行到我們所建立的這段IIFEs,它會將這個匿名函式儲存在Global Execution Context中。



由於我們在函式的最後有加上( ),所以這段函式會立即被執行,也因此,JavaScript會為這個匿名函式建立一個新的Execution Context。



接著,它會去逐行執行我們這個function中的程式碼內容,它發現到我們的程式碼中建立了一個變項,名稱是"greeting",因此,這個變數就被建立在function的這個execution context 中,而不是被建立在Global Execution Context中



因此,透過IIFEs,我們可以發現,在IIFEs中所建立的變數,都不會影響到Global Execution Context所建立的變數,也就是說,透過IIFEs,它避免了我們的變數間可能會互相干擾覆蓋的情況。

IIFEs的實際應用


讓我們先回到一開始的程式碼,這時候我們在函式的外面,用同樣的變數名稱(greeting)去建立。


這時候的結果如下:

你會發現到,雖然同樣都是呼叫greeting這個變數,但是一個是在function execution context內的greeting,一個是在global execution context的greeting,兩者是不會互相影響的。


把它畫成上面的圖型就像這樣,它們兩個是不同的execution context被儲存在不同的記憶體,所以不會相互影響。


如此,我們可以確定,放在IIFEs裡面的變數,並不會影響到其他外層的變數,也不會被外層的變數影響到。

如果我們想要影響到外層變數呢?


雖然我們使用IIFEs的主要目的就是希望不同execution context的變數之間不要互相影響,但若我們希望function execution這層的變數能夠同時影響到Global Execution Context的變數時,我們可以怎麼做呢?

首先,我們多一個參數,叫做global,在代入參數的地方,我們填入物件window,由於我們知道物件是by reference的特性,因此我們可以直接針對window裡面的物件去做改變,像這裡,我就可以直接把global層次的物件改成hola( global.greeting = 'Hola' ):


結果如下,原本在Global Execution Context的Hello,被變更為Hola了:


→回到此系列文章目錄

Share:

0 意見:

張貼留言