前言
首先在前面已經有講過閉包這個東西,但是這個東西自己還是似懂非懂的,所以我將閉包這區塊給挪出來在做一個番外篇紀錄學習。
前文回顧:
‘[JS奇怪的世界]No.38 閉包(一)’
‘[JS奇怪的世界]No.39 閉包(二)’
閉包
首先一樣閉包是什麼?一般來講最簡單的解釋就是一個 function 回傳另一個 function 即為閉包,所以這邊我提供一個簡單範例了解閉包怎麼撰寫 ↓
1 2 3 4 5 6 7 8
| var a = 'Window'; function sayHi (){ var a = 'Closure'; console.log('now is Function.'); return function () { console.log('Hello' + ' ' + a); } }
|
那要執行的方式就是 sayHi(),如果要執行閉包中的 function 就是兩個括號 sayHi()(),這邊會出現兩個 console 是正常的,我故意這麼做的 ↓
Closure
為什麼要寫閉包
那為什麼要學習撰寫 Closure?主要原因有這幾個
- 可以限定變數私有
- 外層的變數可以被內層的
function 給存取
- 內層變數不會被釋放
什麼是內層變數不會被釋放
舉例來講,我們可以用這一篇文章的範例來了解 → 鐵人賽:另一種方式介紹 JavaScript 閉包 然後試著寫一個範例,用數字來做了解。
假設今天小明、小美、小王共同持有 1000 元,然後小明花了 100$,小美花了 50$,而小王花了 700$,所以應該會剩下 150$ 以一般程式來講的話,可能會像這樣撰寫 ↓
1 2 3 4 5 6 7 8 9 10 11
| function myMoney(price) { var money = 1000; return money = money - price; } var count = myMoney;
count(100);
count(50);
count(700);
|
我們會發現一件事情,結果與我們所想的並不一樣 ↓
function
原因是出在每一次執行 count(); 時,JavaScript 都會重新宣告一個新變數叫 money,並且值是 1000,雖然我們有將回傳的變數給做紀錄,但其實當函數執行完畢後,裡面的變數就跟著被釋放掉,所以如果這是我們所希望的結果那這個答案就沒有錯,可是今天我們的題目是大家共同持有 1000$,各自花了錢之後錢包會剩下 150$,所以這時候就要使用 closure 的技巧來解決這個問題,因為我們需要將變數結果給保留下來。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function myMoney() { var money = 1000; return function(price) { return money = money - price; } }
var count = myMoney();
count(100);
count(50);
count(700);
|
closure
我們可以發現結果是我們所想要的,所以這邊讓我們試著解釋一下運作原理。
在前面的範例 ↓
1 2 3 4 5
| function myMoney(price) { var money = 1000; return money = money - price; } var count = myMoney;
|
JavaScript 再運作之後並沒有建立 function myMoney 給變數 count,所以當每次我執行 count(); 都是在建立新的執行環境,這也是為什麼 money 總是等於 1000$。
那閉包呢?前面有講到
閉包就是一個 function 中回傳 function。
所以在閉包的範例 ↓
1 2 3 4 5 6 7 8
| function myMoney() { var money = 1000; return function(price) { return money = money - price; } }
var count = myMoney();
|
其實在 JavaScript 創造階段時,function myMoney 就被創造執行環境,並儲存在變數 count 中,所以因為這個樣子 myMoney 裡面的變數 money 被儲存在記憶體中,當每次執行 count() 時也就可以更新變數 mone。
所以我們可以利用 closure 多做一點來做更多的應用,舉凡將三個各分發一個悠遊卡儲值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| function myMoney(storage) { var money = storage; console.log(money); return function(price) { return { nowMoney: function () { return console.log(money); }, count: function (price) { if(money < price) return console.log('餘額不足,目前餘額: ' + money + ' $'); if (!money <= 0) { return money = money - price; } return console.log('餘額扣除失敗,目前餘額: ' + money + ' $'); } } } }
var ming = myMoney(500);
var mei = myMoney(5000);
var wang = myMoney(30000);
ming().count(100); ming().count(100); ming().count(300);
ming().nowMoney();
mei().count(1600); mei().count(100); mei().count(600);
mei().nowMoney();
wang().count(300);
wang().nowMoney();
|
以上作法參考
透過以上作法我們就可以不停地加入餘額,然後刷卡扣除餘額,所以這邊主要結合了兩篇文章的概念組合而成的閉包分別是: 初次參加保哥的《JavaScript 開發實戰:核心概念篇》感想、鐵人賽:另一種方式介紹 JavaScript 閉包
結論
閉包的應用看起來非常的強大,但是真的要多練習與實際應用才會知道該怎麼使用,
參考文件
鐵人賽:另一種方式介紹 JavaScript 閉包
初次參加保哥的《JavaScript 開發實戰:核心概念篇》感想
談談JavaScript中closure的概念 – Part 1
談談JavaScript中closure的概念 – Part 2
談談JavaScript中closure的概念 – Part 3
談談JavaScript中closure的概念 – Part 4