閉包是由英文的 closure 直接翻譯過來的,所以從字面上看起來,可能也不知道閉包是什麼。
closure 是函式在與其語彙範疇之外被調用,也仍記得並能夠被存取的能力,可說是指向特定範疇的參考。
1 | function foo() { |
bar() 函式能夠存取 foo 的內層範疇。
一般來說我們預期 foo() 的整個內層範疇都會消失,基本上函式離開執行環境時,也會同時將佔用的記憶體空間給釋放出來,但 closure 不會讓這件事發生,foo() 內層的範疇實際上仍在使用,因此不會消失。誰在使用它呢? 就是 bar() 函式本身。
1 | function foo() { |
我們將內層函式 baz 傳給了 bar,並呼叫 bar 的內層函式 fn,包覆 foo() 內層範疇的 closure 就能藉由存取 a 來觀察。
而這些到處傳遞的函式也可以是間接的
1 | var fn; |
不管我們使用了何種方法,將一個內層函式運送到其語彙範疇之外,它依然會保留對他原本宣告處的一個範疇參考。
迴圈與 Closure
closure 最經典的範例
1 | for (var i = 1; i <= 5; i++) { |
我們預期它會每秒印出 1、2、3、4、5,但實際上是每秒印出了五次 6!?
這是因為 setTimeout 在迴圈結束後才執行,因此每次都會出現 6,那到底我們程式中缺少了什麼呢?
我們想要讓迴圈每次迭代都能在該次迭代進行時捕捉到他自己的 i 的一份拷貝,然而,那些計時器函式全都是在迴圈完成後執行,所有的那五個函式,雖然都是在各自的迴圈迭代中分別定義的,但它們都會覆蓋同一個共同的全域範疇,其中實際上只有一個 i 存在。
我們需要更多已被封閉包圍的範疇,也就是說,每次迭代都需要一個新的 closure scope
解決方式 IIFE:
1 | for (var i = 1; i <= 5; i++) { |
利用 IIFE 建立專屬範疇,並有自己的變數,來放置每次迭代 i 的一份拷貝
重返區塊範疇
我們用了 IIFE 來建立專屬每次迭代的新範疇,實際上,我們需要的是各次迭代專屬的區塊範疇。
let 宣告會劫持一個區塊,且每次重新宣告變數 i,並將上一次迭代的結果作為這一次的初始值。
1 | for (let i = 1; i <= 5; i++) { |
區塊範疇和 closure 攜手合作,解決了所有的問題。
模組
1 | function CoolModule() { |
模組模式又稱揭露模組(revealing module),可以將內層函式的資料保持隱藏和私有
,調用時只回傳對外公開的 API,
這個物件回傳最終會指定給外層變數 foo,就能存取 API 的特性方法,例如 foo.doSomething()
要行使模組模式,有兩個必要條件:
- 必須有一個外層的包含函式,而它必須至少被調用一次(每次都會建立一個新的模組實體)
- 這個包含函式至少得回傳一個內層函式,如此這個內層函式才能有覆蓋那個私有範疇的 closure,因此得以存取或修改那個私有狀態
帶有一個函式特性的物件本身並不是一個真正的模組,從一次函式調用所回傳的物件,如果其上只有資料特性,沒有產生 closure 的函式,那它也不是一個真正的模組。
CoolModule()展示了一個獨立的模組創造器,可以被調用數次,每次都會建立一個新的模組實體。
如果只想要單一個實體的時候:
1 | var foo = (function CoolModule() { |
模組函式變成了一個 IIFE,即刻調用,並將回傳值直接指定給我們單一個模組實體式別字 foo
模組只是函式,所以能夠接收參數:
1 | function CoolMoudule(id) { |
為公開 API 的回傳物件取個名稱:
1 | var foo = (function CoolModule(id) { |
在模組實體中保留對公開 API 物件的一個內層參考,就能夠從內部修改那個模組實體,包括新增與移除方法和特性,還有變更它們的值。
參考書籍: 你不知道的 JS-範疇與 Closures
🚀實體工作坊分享
玩轉 Web頁面的前端技術(HTML/CSS/JS) 一日體驗課
最近時賦學苑開了實體體驗課,即使你對程式碼沒有概念也能上手!Lala 會帶你一起做出一個個人品牌形象網站,帶你快速了解前端的開發流程,快跟我們一起玩轉 Web 吧!🚀線上課程分享
線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程想學習更多關於前後端的線上課程,可以參考看看。
Hahow
Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住六角學院
如果你是初學者,非常推薦六角學院哦!剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!
Udemy
Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!也是很多工程師推薦的線上課程網站。