avatar

目錄
閉包(Closure)

閉包(Closure)

函式記得並存取語彙範疇的能力,將外層變數「包」在內層暫存、使用的方式,就是所謂的「閉包」。每一個閉包保存的都是一個獨立的環境。

閉包有兩個特點。

1.變數資料存在於的 Local Scope(函式) 裡,讓外部環境無法直接存取,以確保不被污染。
2.即便這個變數所在的執行環境已經結束,其它函式執行時可以找到它所需的變數。

e.g.

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getSellTicketClosure(){
var counter = 0;
function action(buyer){
counter +=1;
console.log(`(Total Sold: ${counter}) Buyer: ${buyer}`);
}
return action;
}

// 建立 closure
var sellTicket = getSellTicketClosure();

sellTicket('OneJar'); // (Total Sold: 1) Buyer: OneJar
sellTicket('Tony Stark'); // (Total Sold: 2) Buyer: Tony Stark
sellTicket('Steven Rogers'); // (Total Sold: 3) Buyer: Steven Rogers
  1. 在 getSellTicketClosure() 建立 counter 變數,不被 function 外的環境取用。
  2. 在 getSellTicketClosure() 建立,取用 counter 變數的內部函式 action(),運用了函式作用域性質:內部函式可以使用父函式的變數(作用域鍊)。
  3. 將 action() 的函數物件回傳(return)出去給 Global 環境,宣告一個 sellTicket 負責承接。
  4. sellTicket 是一個函數物件,也形成一個閉包。

每一次呼叫閉包,都是建立一個新的函數執行環境。各自獨立,不會互相影響。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getSellTicketClosure(){
var counter = 0;
function action(buyer){
counter +=1;
console.log(`(Total Sold: ${counter}) Buyer: ${buyer}`);
}
return action;
}

var sellTicket1 = getSellTicketClosure();
sellTicket1('OneJar'); // (Total Sold: 1) Buyer: OneJar
sellTicket1('Tony Stark'); // (Total Sold: 2) Buyer: Tony Stark
sellTicket1('Steven Rogers'); // (Total Sold: 3) Buyer: Steven Rogers

var sellTicket2 = getSellTicketClosure();
sellTicket2('Luffy'); // (Total Sold: 1) Buyer: Luffy
sellTicket2('Nami'); // (Total Sold: 2) Buyer: Nami

可以用立即函式(IIFE)簡化語法

Code
1
2
3
4
5
6
7
8
9
10
11
var sellTicket = (function(){
var counter = 0;
return function(buyer){
counter +=1;
console.log(`(Total Sold: ${counter}) Buyer: ${buyer}`);
}
})();

sellTicket('OneJar'); // (Total Sold: 1) Buyer: OneJar
sellTicket('Tony Stark'); // (Total Sold: 2) Buyer: Tony Stark
sellTicket('Steven Rogers'); // (Total Sold: 3) Buyer: Steven Rogers

e.g.

另一個簡單範例

Code
1
2
3
4
5
6
7
8
9
10
11
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}

var baz = foo();

baz(); // 2

參考:
https://ithelp.ithome.com.tw/articles/10209465
https://www.fooish.com/javascript/function-closure.html
https://blog.techbridge.cc/2018/12/08/javascript-closure/