javascript閉包的使用–按鈕切換

yangtoude發表於2018-08-30

閉包實現按鈕狀態切換

看下面的程式碼:

 1 var toggleBtn = document.getElementById(`toggle`);
 2 
 3 var toggleFun = (function() {
 4   var checked = true;
 5 
 6   return function() {
 7     var color = checked ? `red` : `white`;
 8     toggleBtn.style.backgroundColor = color;
 9     checked = !checked;
10   };
11 })();
12 
13 // 切換按鈕
14 toggleBtn.addEventListener(`click`, toggleFun);

解釋
上面的程式碼實現了點選按鈕切換樣式的功能,它用到了js的閉包特性。簡單解釋下:
toggleFun為一個立即執行函式,執行後toggleFun被賦值為內部函式:

1 toggleFun = function() {
2     color = checked ? `red` : `white`;
3     toggleBtn.style.backgroundColor = color;
4     checked = !checked;
5 }

這個函式用到了外部函式的checked變數,這也是checked變數在立即執行函式執行完成後未被銷燬的原因,因為還有其他地方用到了它。那麼這個內部函式被用作事件監聽器的回撥函式,每點選一次就會被呼叫一次,從而可以通過更改checked的值來實現按鈕切換效果。立即執行函式內的函式被全域性下的toggleFun變數引用了,這就建立了一個閉包。

簡而言之,閉包的作用就是在立即執行函式執行完並返回後,使得javascript的垃圾回收機制不會收回立即函式所佔用的資源,因為立即執行函式的內部函式依賴立即執行函式中的變數。
額,上面寫的太囉嗦了,下面把程式碼稍微改下,加些註釋就會更加清晰:

 1 var toggleBtn = document.getElementById(`toggle`);
 2 
 3 var outerFun = function() {
 4   var checked = true;
 5 
 6   // innerFun宣告時用到了outerFun的區域性變數
 7   var innerFun = function() {
 8     var color = checked ? `red` : `white`;
 9     toggleBtn.style.backgroundColor = color;
10     checked = !checked;
11   };
12 
13   return innerFun;
14 };
15 
16 var toggleFun = outerFun(); // toggleFun指向innerFun
17 
18 // 切換按鈕,每次點選都會呼叫innerFun
19 toggleBtn.addEventListener(`click`, toggleFun);

不用閉包,用全域性變數
其實不用閉包也能實現按鈕切換,不過就得用到全域性變數來儲存按鈕狀態:

 1 var toggleBtn = document.getElementById(`toggle`);
 2 var checked = true; // 全域性變數儲存按鈕狀態
 3 
 4 var toggleFun = function() {
 5   var color = checked ? `red` : `white`;
 6   toggleBtn.style.backgroundColor = color;
 7   checked = !checked;
 8 };
 9 
10 toggleBtn.addEventListener(`click`, toggleFun);

但全域性變數用多了會不好維護,程式碼不好控制。


這篇文章最初發表在我自己折騰的部落格站點上:javascript閉包的使用–按鈕切換,該部落格用了一位前輩開源的原始碼,基於thinkjs和vuejs開發,歡迎大家來逛逛。

相關文章