加薪閉包 - Closure

Free Variable這則貼文裡,我們已經看過了free variable是什麼啦,這次我們要來看看什麼是JavaScript的closure。在看closure之前,我們先一起回顧一下用closure的好處:有避免產生global變數、避免跟別人的程式碼發生衝突、避免讓變數意外得被外界程式修改而導致bug產生等。既然它有這麼多好處,一定要掌握它!要掌握closure首先我們要知道,當一個function用到了free variable,會發生什麼事,我們先看看下面的程式碼片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getIncreaseSalaryFunc() {
let salary = 0;

function increaseSalary() {
let message = "Salary is ";
salary = salary + 1000;
console.log(message + salary);
}

return increaseSalary;
}

let increaseSalary = getIncreaseSalaryFunc();
for (let i = 0; i < 99999; i++) {
increaseSalary(); // This prints my current salary
}

我們可以看到increaseSalary function裡面用的salary就是一個free variable,它在increaseSalary function裡面沒有被建立,而是被建立在外面的getIncreaseSalaryFunc function裡。在這種情況下,increaseSalary function還是可以存取到salary變數。這是怎麼一回事呢?我們先來看看closure是什麼意思:

Closure是一個function,附上一個包含所有free variables的referencing environment

increaseSalary function被建立時,closure就產生了,而當increaseSalary function被return出去時,可以想成是把整個closure回傳出去。於是,當包含free variable的function被執行時,JavaScript會從closure裡的referencing environment尋找free variable的數值。這也就是為什麼,在裡面的increaseSalary function可以存取到外面的getIncreaseSalaryFunc function的salary變數啦!

到這裡,我們再來看看用closure的好處!這麼做的其中一個好處是,我們可以避免function要用的變數被外界存取到,想想如果有目的不同的程式碼存取到名字一樣的變數,會不會發生意外的side effect呢?我們可以回過頭來看看呼叫increaseSalary()的地方,在這裡是存取不到salary變數的,也就避免salary變數被increaseSalary function和getIncreaseSalaryFunc function以外的程式碼存取到啦!