這是一門在Udemy 課程,是同學介紹的。主要是因為想要運用到過年前這段時間好好的增進自己的JavaScript的基礎能力,讓自己能往前端工程師更近一步。主要還是會以筆記的形式做呈現!
IIFE,全稱Immediately Invoked Functions Expressions(立即執行函式)
在之前有提到建立 function 的方法通常有 function statement 和 function expression 這兩種方式,
而IIFEs
指的就是透過 function expression 的方式來建立函式,並且立即執行它。
如下列程式碼:
1 | // function statement |
輸出結果為:
1 | Hello John |
前面兩段code在之前的章節我們都有學習到,但第三段code看起來很像是第二段code,只是多了點東西。其實這就是IIFE
,用function expression的方式建立function後直接在最後面加上()。
我們用下面兩張圖片來說明會更加了解:
這張圖片就是我們之前學的function expression,我們可以看到,當我們console.log(greeting)出來的會是一個function。
但當我把function用()
包起來並且再加上一個()
後,他就會直接執行這個function裡的內容並回傳字串。
另外這邊還有一個重點,在使用 IIFE
的寫法後,他回傳的內容會是字串,因此我們沒有辦法再次執行它。
如果我們強制在後面加上(),例如:
1 | // using an Immediately Invoked Function Expression (IIFE) |
我們會得到:
1 | TypeError: greeting is not a function |
所以我們要特別注意這邊,避免出現錯誤(現在才知道我之前為什麼有時候會出現這個東西了)
在之前我們有提到過expression 的概念:輸入後能夠直接回傳值的一串程式,我們一般會把它存成一個變數,但是它不一定要被存成一個變數。
當如果想在function也做到,這是後我的第一個想法會是:
1 | // ❌ 錯誤寫法 |
這時候我會得到一個錯誤:
1 | SyntaxError: Function statements require a function name |
之所以會錯誤是因為我用 function 做為開頭,所以JavaScript 引擎在解析程式碼的時候,它會認為你現在要輸入 function statement,但我卻沒有給這個function一個的名稱,於是它無法正確理解這段程式碼便拋出錯誤。
所以我們只要跟JavaScript 引擎說,這一整個並不是function statement就可以了。
1 | (function(name) { |
這是我們最常使用的做法:用括號 () 把 function(){ …} 包起來。
因為課堂上有說到,我們只會在括弧內放入 expression,例如 (3+2),而不會放 statement 在括弧內,所以JavaScript 就會以 expression 的方式來讀取這段函式。因此這個 function 會被建立,但是不會被存在任何變數當中,也不會被執行。
這時候再套用到剛剛學到的IIFE,在最後面加上()
1 | var firstname = 'John'; |
這段我們要來探討,為什麼我們需要使用IIFEs?
還記得之前課堂上有提到的一個名詞:namespace。
namespace的使用是為了避免變項名稱重覆所造成的問題,而IIFEs也很類似,他也是可以避免我們所建立的變項名稱因為覆蓋而造成影響。
接下來我們要了解在JavaScript引擎實際發生了什麼,我們就拿下面的範例來說明:
1 | (function(name) { |
套用之前所學的,當我執行剛剛那段code時,會先建立Global Execution Context(裡面是空的,因為我們沒有設立變數)
接下來JavaScript引擎會執行這段IIFEs,它會將這個匿名函式儲存在Execution Context中。
由於我們在function的最後有加上( ),所以這段function會立即被執行。JavaScript引擎會去逐行執行我們這個function中的程式碼內容,當它發現到我們的程式碼中建立了一個變數var greeting = 'Hello';
,因此這個變數就被建立在這個execution context 中。
因此,透過IIFEs,我們可以發現,在IIFEs中所建立的變數,都不會影響到Global Execution Context所建立的變數,也就是說,透過IIFEs,它避免了我們的變數間可能會互相干擾覆蓋的情況。
在課堂的最後有提到,如果我要讓function execution這層的變數能夠同時影響到Global Execution Context的變數時,我該怎麼做?
其實也是之前有提到的一個觀念:by reference
由於我們知道物件是by reference
的特性,因此我們只要把全域變數帶入就可以了,因此我們必須要多一個參數,叫做global
,在帶入參數的地方放入window
(全域變數),之後再直接針對window裡面的物件去做改變。如下:
1 | var greeting = "Hola"; |