JavaScript Closure 與 IIFE 筆記
Closure (閉包)
一句話解釋閉包:讓函式能存取其被宣告當下作用域 (scope) 的變數。可以想像成函式能「飲水思源」。
來看下面這段程式碼:當我們執行 scoreCounting,它會回傳一個新函式給 getScore。即使 getScore 已經是在外部(全域環境)宣告,而且 scoreCounting 早就執行完畢,getScore 這個函式在執行時,還是能存取 scoreCounting 裡面的 score 變數。
這是因為函式能存取哪些變數,是看它「在哪裡被建立」而不是「在哪裡被呼叫」。getScore 內部的函式是在 scoreCounting 裡面被創造出來,所以能記住 score 這個變數。這種現象就叫做閉包(Closure)。
Closure Example 1
下面的程式碼中,變數 f 最初被設定成在函式 g 裡面建立的函式,所以執行 f() 時可以用到 g 裡的變數 gVariable。
後來我們用函式 h 把 f 重新指定成另一個在 h 裡面建立的函式,這時再執行 f(),就可以用到 h 裡的變數 hVariable。
Closure Example 2
在下面的例子中,雖然 setTimeout 裡的函式是在全域環境執行,但因為它是在 boardPassengers 這個函式裡面建立的,所以可以用到 perGroup 這個變數。
Closure Example 3
事件監聽器的回呼函式同樣能透過閉包存取 header 變數。
IIFE (Immediately Invoked Function Expression)
在 Scope 筆記中提到:函式會創造作用域,因此外部無法直接存取函式內部變數,達成資料保護的效果。
數據封裝 (Data Encapsulation)
以下程式碼存在資料外洩的風險:
透過 IIFE,可以在宣告同時立即執行,並避免外部存取:
IIFE 與 ES6 Block Scope
在 ES6 中,屬於 Block Scope 的 const 、 let 出現之後,只要創造出 Block Scope ,就無法從外部存取以 const 、 let 宣告的變數,也因此 IFFEs 的使用率漸漸的下降。