這篇和前幾篇與之後比較沒有關聯,但因為突然有看到,想說寫一下
在程式設計中,閉包(Closure)是一個很重要的概念
簡單來說:
閉包就是「函式可以記住並存取它外層作用域的變數」,即使這個外層函式已經執行結束
因為閉包能記住外部變數,所以它常被用來做狀態保存,像是一個計數器、一個暫存快取,或者模擬私有變數
舉例來說:
func makeCounter() -> () -> Int {
var count = 0 // count 是 makeCounter 裡的區域變數
// 回傳一個閉包,這個閉包捕獲了外層的 count
let counterClosure: () -> Int = {
count += 1
return count
}
return counterClosure
}
let counter1 = makeCounter()
print(counter1()) // 1
print(counter1()) // 2
print(counter1()) // 3
let counter2 = makeCounter()
print(counter2()) // 1
print(counter2()) // 2
print(counter1()) // 4 (counter1 保持自己的狀態)
這裡的 count
原本應該在 makeCounter
執行完後就消失,但因為閉包「捕獲」了它,讓 count
可以持續存在並保存狀態
Note: 這裡說的「捕獲」和之前事件的冒泡與捕獲是完全不一樣的事情喔!
useState
就是閉包概念)function useState(initialState) {
let state = initialState;
function getState() {
return state;
}
function setState(updatedState) {
state = updatedState;
}
return [getState, setState];
}
const [count, setCount] = useState(0);
console.log(count()); // 0
setCount(1);
console.log(count()); // 1
setCount(500);
console.log(count()); // 500
閉包可以保存計算結果,避免重複運算
function memoize(fn) {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (key in cache) {
return cache[key];
} else {
const val = fn(...args);
cache[key] = val;
return val;
}
};
}
const sum = (a, b) => a + b;
const memoizedSum = memoize(sum);
console.log(memoizedSum(2, 2)); // 運算 -> 4
console.log(memoizedSum(2, 2)); // 快取 -> 4
var counter = (function () {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function () {
changeBy(1);
},
decrement: function () {
changeBy(-1);
},
value: function () {
return privateCounter;
},
};
})();
console.log(counter.value()); // 0
counter.increment();
counter.increment();
console.log(counter.value()); // 2
counter.decrement();
console.log(counter.value()); // 1
privateCounter
無法直接被外部存取,只能透過 increment
和 decrement
修改,這就是閉包達成封裝的效果。
潛在記憶體洩漏:
閉包會「捕獲」外部變數,這些變數就不會被垃圾回收(GC)回收,可能造成效能浪費。
→ 解法:只在需要的時候使用閉包。
你可能會問:「不就是要保存狀態嗎?為什麼不用全域變數或物件就好?」
這裡比較三種方法:
全域變數
var globalCount = 0
func incrementGlobalCount() {
globalCount += 1
print(globalCount)
}
incrementGlobalCount() // 1
incrementGlobalCount() // 2
物件導向(OOP)
class Counter {
var count = 0
func increment() {
count += 1
print(count)
}
}
let counterA = Counter()
counterA.increment() // 1
counterA.increment() // 2
閉包(函式導向)
https://ithelp.ithome.com.tw/articles/10193009