📄 Closure
1. What is Closure ?
什麼是 Closure ?
要理解閉包,需要先明白 JavaScript 的變數作用域,以及 function 是如何訪問外部變數的。
Variable Scope(變數作用域)
在 JavaScript 中,變數的作用域分為兩種,分別是 global scope & function scope。
// global scope
let a = 1;
function parentFunction() {
// function scope
let b = 2;
function childFunction() {
let c = 3;
console.log(a, b, c); // print 1 2 3, can access global scope & function scope
}
childFunction();
}
parentFunction();
console.log(a); // print 1, can access global scope
console.log(b, c); // 產生錯誤,無法存 取 function scope 內的變數
Closure example
Closure 的觸發條件是,有一個子函式定義在父函式內,且透過 return 的方式回傳,達到保存子函式內的環境變數(等於迴避了 Garbage Collection(垃圾回收機制)
)。
function parentFunction() {
let count = 0;
return function childFunction() {
count += 1;
console.log(`目前計數:${count}`);
};
}
const counter = parentFunction();
counter(); // print 目前計數:1
counter(); // print 目前計數:2
// count 變數不會被回收,因為 childFunction 仍然存在,並且每次呼叫都會更新 count 的值
但要注意,因為閉包會將變數保存在記憶體中,所以如果變數過多,會導致記憶體占用過大(不能濫用閉包),進而影響效能。
2. Create a function that meets the following conditions
建立符合下述條件的 function(使用閉包觀念來處理)
plus(2, 5); // output 7
plus(2)(5); // output 7
First Solution : two functions
將兩個 function 進行分拆後處理
function plus(value, subValue) {
return value + subValue;
}
console.log(plus(2, 5));
// use closure save variable
function plus(value) {
return function (subValue) {
return value + subValue;
};
}
console.log(plus(2)(5));
Second Solution : single function
當然第一種解法有不小的機率被 reject,所以需要嘗試合併在同一個 function。
function plus(value, subValue) {
// 利用每次傳入參數的多寡來判斷
if (arguments.length > 1) {
return value + subValue;
} else {
return function (item) {
return value + item;
};
}
}
console.log(plus(2, 5));
console.log(plus(2)(5));
3. Please take advantage of the closure feature to increase the number
請利用閉包的特性,將數字遞增
function plus() {
// code
}
var obj = plus();
obj.add(); // print 1
obj.add(); // print 2
First Solution : return variable
這邊不使用 Arrow Function,改用一般 function 的形式。
function plus() {
let cash = 0;
let counter = {
add() {
cash += 1;
console.log(cash);
},
};
return counter;
}
var obj = plus();
obj.add();
obj.add();
Second Solution : return object
前一個解法中,也可以直接將 object 包裹在 return 中
function plus() {
let cash = 0;
return {
add: function () {
cash += 1;
console.log(cash);
},
};
}
var obj = plus();
obj.add();
obj.add();