閉包(Closure)
函式記得並存取語彙範疇的能力,將外層變數「包」在內層暫存、使用的方式,就是所謂的「閉包」。每一個閉包保存的都是一個獨立的環境。
閉包有兩個特點。
1.變數資料存在於的 Local Scope(函式) 裡,讓外部環境無法直接存取,以確保不被污染。
2.即便這個變數所在的執行環境已經結束,其它函式執行時可以找到它所需的變數。
e.g.
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
|
- 在 getSellTicketClosure() 建立 counter 變數,不被 function 外的環境取用。
- 在 getSellTicketClosure() 建立,取用 counter 變數的內部函式 action(),運用了函式作用域性質:內部函式可以使用父函式的變數(作用域鍊)。
- 將 action() 的函數物件回傳(return)出去給 Global 環境,宣告一個 sellTicket 負責承接。
- sellTicket 是一個函數物件,也形成一個閉包。
每一次呼叫閉包,都是建立一個新的函數執行環境。各自獨立,不會互相影響。
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)簡化語法
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.
另一個簡單範例
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/