前言
在現實生活中,閉包closure的可以說是無所不在,或許你現在已經很頻繁的使用它,但你自己卻不知道而已。
今天這篇文章,希望能讓大家簡單理解閉包Closure,所以不會有其他太複雜的內容,讓大家快速上手!
什麼是閉包Closure? 主要用途是什麼
閉包這個詞,顧名思義就是「封閉」的一個包。
但封閉的主要用途是什麼呢?就是:
讓每個功能相同的function,對應到每個獨立的環境變數,且互不相干擾。
看不懂?沒關係,就讓我們來舉些例子!
銀行帳戶
我們用銀行帳戶來舉例,如果今天A用戶的銀行帳戶程式碼長這樣:
// ----銀行帳戶程式碼 Part1----// A的存款有1000元
let balance = 1000// 共用的提款卡功能
function withdraw (amount) {
balance = balance - amount
}// 用戶A提100元
withdraw(100)// 用戶B提200元
withdraw(200)
A:乾!我的錢怎麼被B提走了?
因為 withdraw
function是共用的,所以B也能提走A的錢,但這邏輯肯定是行不通的。
沒人會想讓別人提走自己的錢,所以讓我們來改一下程式碼:
// ----銀行帳戶程式碼 Part2----// A的存款有1000元
let balanceA = 1000// B的存款有2000元
let balanceB = 2000// A專屬的提款卡功能
function withdrawA (amount) {
balanceA = balanceA - amount
}// B專屬的提款卡功能
function withdrawB (amount) {
balanceB = balanceB - amount
}// 用戶A提100元
withdrawA(100)// 用戶B提200元
withdrawB(200)
A:耶!把錢Bang回來~
改成這樣的寫法,我們把兩個帳戶(環境)區分開來,讓他們各自提各自的錢,這樣看上去挺完美的…結案!
但我們忽略了一個很重要的問題:
一般的銀行不會只有兩個用戶
所以如果我們幫每個用戶都寫了一份「專屬」的程式碼,那肯定會由臭又長很崩潰…
// ----銀行帳戶程式碼 Part3----// A的存款有1000元
let balanceA = 1000// B的存款有2000元
let balanceB = 2000// C的存款有2000元
let balanceC = 2000// D的存款有2000元
let balanceD = 2000...
...
..// A專屬的提款卡功能
function withdrawA (amount) {
balanceA = balanceA - amount
}// B專屬的提款卡功能
function withdrawB (amount) {
balanceB = balanceB - amount
}// C專屬的提款卡功能
function withdrawC (amount) {
balanceC = balanceC - amount
}// D專屬的提款卡功能
function withdrawD (amount) {
balanceD = balanceD - amount
}....
...
這時候,我們需要一個方法,既可以快速建立帳戶,又可以讓每個帳戶的環境互不相干擾,也就是建立每個「封閉」的帳戶給用戶們。
這時候,我們的救星,閉包Closure登場了!
閉包Closure,一人一戶
我們再次改寫我們的程式碼,這次我們建立一個「提款功能製造機」來幫助我們生產許多帳戶:
// ----銀行帳戶程式碼 Part4----// 帳戶製造機
function accountCreator(initBalance, user) {
let balance = initBalance
// 製造成功後,返回提款功能
return function (amount) {
balance = balance - amount
console.log(user, balance)
}
}// 快速建立多個帳戶!
const withdrawA = accountCreator(1000, 'A')
const withdrawB = accountCreator(2000, 'B')
const withdrawC = accountCreator(3000, 'C')
const withdrawD = accountCreator(4000, 'D')// 結果
withdrawA(100) // A 900
withdrawB(200) // B 1800
withdrawC(300) // C 2700
withdrawD(400) // D 3600
上面的邏輯很簡單,我們建立了一個提款功能製造機。
但看起來好像每次調用提款功能都會吃到「一樣」的balance? 錯!
實際上,每次調用這個製造機,我們都是建立一個全新的balance封閉在 accountCreator
裡頭,然後「生產」一個全新的提款function連結對應balance。
所以調用這個function製造提款功能的時候,都會建立每個人「專屬的balance」跟「專屬的提款function」。
對A B C D用戶來說,他們等於是拿到了各自專屬的提款卡,然後對應到各自專屬的餘額(balance變數)。
這就是閉包closure帶給我們的方便性:
讓每個功能相同的function,對應到每個獨立的環境變數,且互不相干擾。
我們再來看看一些現實上的例子。
現實範例,Redux的createStore
我們拿Redux的createStore來當作閉包的例子!這裡是原始碼,大家有興趣可以去看看,我們下面就用簡化版的來講解就好。
有學過Redux的人一定都知道,store本身裡包含了許多功能,這些功能其實也用到了閉包closure的原理來做封裝!
// 簡化版function createStore () {
...
...
function dispatch() {...}
function getState() {...}
...
... // 關鍵:建立了store物件,然後返回。
const store = { dispatch, getState ... } // 然後return,dispatch、getState等等功能都被封裝
return store
}
從上面的程式碼來看,如果你今天要建立多個store(雖然應該不會有人這樣做),每個store的環境都會是獨立且分開來的,這也是閉包closure的一個實際例子!
結尾
以上就是對閉包closure的基本教學,雖然沒有涵蓋到更多複雜的東西,但相信足以應付大部分的開發情況。
讓我們再來複習一次~
讓每個功能相同的function,對應到每個獨立的環境變數,且互不相干擾。
希望這篇文章能讓大家快速上手閉包closure!
想持續關注我的話
- 去Medium追蹤給他按下去~!
- 去Facebook粉專按按讚~!
- 去Youtube頻道訂閱,每週三都直播聊聊大家想問的問題~!
- 加入我創的Line社群,群組目前有1300多人,可以一起進來交流分享經驗跟技術。
- Line社群點我加入:https://reurl.cc/V3WjGZ