根據 MDN 的說法閉包是函式以及該函式被宣告時所在的作用域環境 ( lexical environment ) 的組合
語法作用域 ( lexical scoping )
function init() {
let name = 'John';
function getName() {
return name;
}
getName();
}
init(); // John
getName() 並無定義 name 這個變數,但它可以參考語法作用域的變數,因此能取用到父函式宣告的變數 name,如果父函式沒找到,它可以繼續往上找,一路找到全域變數。global 的 lexical scope 就是 null。
閉包 ( Closure )
function init() {
let name = 'John';
function getName() {
return name;
}
return getName;
}
let doInit = init();
doInit(); // John
function init() {
let name = 'John';
function getName() {
console.log(name); // 不能在 name 被宣告前使用
let name = 'Jay';
}
return getName;
}
在函數內部捕獲和保存當前語境中的變數和狀態,並將其留存在函數外部,以便在後續的呼叫中繼續使用,即使當前作用域已經被銷毀了。
應用場景
狀態保存
function useState(initialState) {
let state = initialState;
function getState() {
return state;
}
function setState(updatedState) {
state = updatedState;
}
return [getState, setState];
}
const [count, setCount] = useState(0);
count(); // 0
setCount(1);
count(); // 1
setCount(500);
count(); // 500
模擬私有變數
function createCounter() {
let count = 0;
function counter() {
count++;
console.log(count);
}
return counter;
}
const counter1 = createCounter();
counter1(); // 1
counter1(); // 2
counter1(); // 3
const counter2 = createCounter();
counter2(); // 1
counter2(); // 2
counter2(); // 3
⚠️ 閉包是很強大的功能,但過度使用容易造成記憶體流失 (memory leak)
-
以下程式碼會依序輸出什麼呢?
function closure() { let counter = 0; return () => { counter++; console.log(counter); }; } const counter1 = closure(); const counter2 = closure(); counter1(); counter1(); counter2(); counter1();
答案:1, 2, 1, 3
Top comments (0)