JavaScript 核心觀念(36)-函式以及 This 的運作-立即函式
前言
關於立即函式是一個非常常見的技巧,在許多框架上都可以看到的技巧。
立即函式
立即函式是什麼呢?立即函式全名為「immediately-invoked function expression」也就是所謂的「IIFE」,完整的中文名稱為「立即呼叫函式表達式」,而這是什麼意思呢?在前一章節我們有了解到具名陳述式是必須被呼叫才會執行的
1 | function fn() { |
而 IIFE 則不用透過我們的呼叫,在程式碼運行時,就會自己執行。
1 | (function() { |
IIFE 的關鍵在於最尾段的括號 ()
,通常可能你會看到兩種撰寫方式
1 | (function() { |
這兩種方式並沒有絕對的答案,因為都是可以正常執行 IIFE,在這邊我們可以看到 IIFE 並不具有名稱,也就是所謂的匿名函式的一種,但與前面所看到的匿名表達式又不同,一般的匿名表達式是必須被呼叫才會執行裡面結果
1 | var fn = function() { |
這邊可能會有人疑惑說以下的寫法算是什麼?
1 | (function fn() { |
其實也是 IIFE 的一種,但 function 的名稱其實是不用撰寫的,因為沒有必要,但 JavaScript 不會提示你不用寫。
因此 IIFE 第一個特點這邊就可以很明顯感受出來,也就是立即執行函式(廢話),但 IIFE 還有另一個特點,也就是當它執行完畢之後,你就無法再次呼叫甚至是外層呼叫,而且宣告在裡面的變數,只有 IIFE 內可以取用
1 | (function fn() { |
因此我們這邊可以透過 MDN 了解關於 IIFE 的說明
IIFE (Immediately Invoked Function Expression) 是一個定義完馬上就執行的 JavaScript function。
除此之外,這邊還有一個重點要注意
這樣的寫法可以避免裡面的變數污染到 global scope。
這是什麼意思呢?IIFE 最大重點觀念在於認清作用域,在還沒有 block 作用域,也就是 ES6 之前,其實非常容易發生所謂的污染問題,因為 var
宣告的變數是基於 function
作為作用域,因此以下程式碼就非常容易污染到 Window
1 | for(var i = 0; i < 10; i++) { |
因此這種狀況我們就必須去避免開發時污染到 Window,這時候就可以使用 IIFE 去侷限作用域,讓變數 i
只活在 IIFE 內
1 | (function() { |
那這邊你可能會問,對外無法取得 IIFE 內部的變數與函式,那可以對內傳遞參數嗎?答案是可以的,寫法則是如下
1 | (function(name) { |
而且本身因為 IIFE 就是一個表達式,所以也可以利用 return
並搭配一個變數來接收 IIFE
1 | var name = (function(name) { |
最後 IIFE 有一個雷點很常發生也就是「;
」,如果沒有正確撰寫 ;
就會出現「Uncaught TypeError: (intermediate value)(...) is not a function
」的錯誤
1 | (function(name) { |
而該錯誤的解法就是在括號前面補上 ;
即可
1 | (function(name) { |
這邊主要的錯誤原因與很前面的章節「JavaScript 核心觀念(12)-運算子、型別與文法-ASI 自動插入分號」有關係。
那麼最後來講一下為什麼要使用 IIFE,IIFE 最主要目的是避免污染到全域執行環境並照成污染與衝突,因此在以下範例程式碼,雖然變數是建立在函式內,但 function
卻是直接建立在全域執行環境下
1 | function getName() { |
因此這時候若有一個類似同名的變數或是函式就會發生衝突。
雖然現在 ES6 出了 let
與 const
,但使用變數宣告的記憶體是無法被刪除的,因此當宣告越來越多時,效能自然就會比較差,在此 IIFE 還是有它一定的功用。