閉包實現按鈕狀態切換
看下面的程式碼:
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開發,歡迎大家來逛逛。