Closure
JavaScript 的記憶體管理
垃圾回收器(garbage collector) 系統
- 追蹤記憶體分配的使用情況,以便自動釋放一些不再使用的記憶體空間
- 全域變數關閉瀏覽器頁面,才會回收
- 區域變數的值,沒有用到就會被自動回收
簡單理解
- 閉包 = 內層函式 + 外層函式的變數
- 當內層函式用到了外層的變數,就構成了閉包
- 內部函式除了能夠取得函式外部的變數,還可以記住這個變數
範例 1
function outer() { const a = 1 function f() { console.log(a) } f()}outer() // 1
範例 2
function outer() { let i = 1 function fn() { console.log(i) } return fn}const fun = outer()fun() // 1
應用 1 — 狀態保存
- 通常會 return 一個匿名函式,可以取得到外層函式的變數
- 用一個變數來取出回傳的函式
- 因為
result
指向count
這個函式(全域),myCount
不會被回收 myCount
計算後的結果會被儲存下來
範例
//function count() { let myCount = 0 return function () { myCount++ console.log(`被調用${myCount}次`) }}const result = count()result() // "被調用1次"result() // "被調用2次"
應用 2 — 緩存機制
- 因為閉包原理,
cache
變數可以被 return 的函式取得 - 能夠用
cache
來放想要緩存的東西,在執行前先檢查是否存在快取 - 可以避免重複計算
function expensiveFunction() { // 這裡是複雜的操作 console.log('Executing expensive operation...') return 'Expensive Result'}function createCache() { let cache = {} return function (key, func) { if (!cache[key]) { cache[key] = func() } return cache[key] }}const cachedFunction = createCache()// 首次調用,將計算結果緩存// 輸出: Executing expensive operation... Expensive Resultconsole.log(cachedFunction('test', expensiveFunction))// 第二次調用,直接從緩存回傳結果// 輸出: Expensive Result(不會再次執行 expensiveFunction)console.log(cachedFunction('test', expensiveFunction))
應用 3 — 模擬私有變數
- 開發的程式碼內部細節,並不想讓外部來獲取時
- 可以避免變數被直接修改,維持穩定性
function createBankAccount(initialBalance) { let balance = initialBalance // 私有變數 return { deposit: function (amount) { balance += amount console.log(`存款後餘額:${balance}`) }, withdraw: function (amount) { if (amount <= balance) { balance -= amount console.log(`提款後餘額:${balance}`) } else { console.log('餘額不足') } }, getBalance: function () { return balance // 提供對私有變數的讀取方式 } }}const account = createBankAccount(100)account.deposit(50) // 存款後餘額:150account.withdraw(20) // 提款後餘額:130console.log(account.getBalance()) // 130console.log(account.balance) // undefined,無法直接訪問私有變數
需注意
- 當使用閉包時,因為變數會常駐在記憶體中不會清除
- 若使用過多,可能導致內存泄露(memory leak)
參考資料
# JavaScript # 閉包