(Day14) 閉包 (Closure) 介紹
前言
閉包算是在 JS 中常聽到,卻不容易使用的一個方法,更多狀況是不小心用出來,因此出 bug
閉包與記憶體
在介紹閉包之前,先來看看下面範例:
1 | function randomString(length) { |
randomString
是一個會根據設定執行數次,產生亂碼字串的方法,而這亂碼字串會藉由 return result
回傳,最後又在 push 至 demoData 變數上。
使用 chrome 無痕模式來觀察 Memory ,可以發現在執行上述程式碼時,記憶體使用了 1.3 MB
再來執行另外一段非常相近的程式碼,來看看他的記憶體使用量:
1 | function randomString(length) { |
可以發現這個範例記憶體增使用量將近 21MB ,這是因為第二個範例 demoData
變數是被放在外層也就是全域( window)底下,而 demoData
變數此時是能在被呼叫、使用的。
而第一個範例中, demoData
是在函示裡頭, demoData
變數則會跟著 getData
執行完畢時,一同被釋放記憶體,此時 demoData
也是無法被呼叫的,因此兩者記憶體落差十分大。
之所以要先講這一段是因為,記憶體可以說是閉包的一個重點。
閉包範例與解釋
接下先來看看閉包的一個簡單範例
1 | function openFn() { |
在上面範例中 ClosureFn
其實就是閉包,若要執行這個閉包可以直接使用 openFn()(100)
其就會被執行,不過一般來說我們不會直接使用兩個 ()()
小刮號做執行,而是像上面範例中使用 openFn()
並且再用一個變數來做指向。
而上面有提到記憶體是閉包的重點,關於這一點我們可以看看連續執行 useClosure()
後回傳的值會不斷疊加,然而 ClosureFn
閉包函示內部雖然沒有 let num = 100
,不過閉包內部會因為 num = num + newNum
這段程式碼,有使用到 num
變數,因此按照作用域的規則,會訪問(參考)外層函式的 let num
變數,因為這個訪問(參考)的動作,就會讓 num
變數的記憶體『不被釋放』,因此當正是因為這個『不被釋放』,我們使用 useClosure(10)
的值才可以不斷被疊加。
這邊也試者使用圖片來增加對閉包的理解:
之所以要使用閉包,就是因為可以透過不同變數、常數,讓閉包回傳資料各自獨立,某些需要重複使用程式碼的狀況就可以使用閉包,例如
1 | function openFn() { |
下篇則會介紹閉包延伸運用。
參考文獻
- JavaScript 核心篇 (六角學院)
- JavaScript 核心觀念(38)-函式以及 This 的運作-閉包 Closure