不斷積累和整理在JavaScript中常見的閉包問題,不斷加深理解和學習運用:javascript
參考MDN網址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closuresjava
閉包的官方定義: 閉包是由函數以及建立該函數的詞法環境組合而成。這個環境包含了這個閉包建立時所能訪問的全部局部變量(摘自MDN)瀏覽器
閉包的簡單理解:但願在另外一個做用域(好比在global中)訪問局部做用域中的某個變量或函數閉包
(在谷歌瀏覽器中調試,發生閉包會有closure字樣提示)異步
問題一:閉包的「雛形」:在全局做用域中訪問某局部做用域中的變量或函數:函數
function fn() { var name = 'zs'; return function () { return name; } } var f = fn(); var n = f(); //或者這樣寫: var n= fn()(); console.log(n) //zs
問題二:用閉包解決在for循環中綁定事件的問題性能
假設不使用閉包解決這個問題,點擊綁定的li的值輸出的都是最後的一個值,由於觸發點擊事件的時候for循環已經結束了,且在for循環的做用域中 i 的值不斷被覆蓋學習
var list = document.getElementByTagName('li'); for (var i = 0 ;i < list.length ;i++){ var li = list[i]; ( function (index){ li.onclick = function(){ alert( index ); } })(i) }
自執行函數從全局做用域中訪問for循環裏面的 i, 給每一個 i 都新開創了一個做用域,讓它保存i的值 spa
但過多的開創獨立做用域,會形成額外的開銷消耗性能,因此閉包有利有弊,像上面這種問題可使用let來解決調試
延伸:其餘解決改問題的方法(使用let定義i)
var list = document.getElementByTagName('li'); for (let i = 0 ;i < list.length ;i++){ li.onclick = function(){ alert( i ); } }
問題三:用閉包解決在for循環中 setTimeout() 的問題
console.log(111) for ( var i = 0 ; i<3 ; i++){ setTimeout(function () { console.log(i) }, 0 ) } console.log(222) 最後的執行結果: 111 222 3 3 3
當js執行到setTimeout時會將其自動放入異步隊列中去等待,直到主代碼執行完後再去執行異步隊列中的代碼,因而3個3會在最後出現
使用閉包的方法避免這種狀況:
console.log(111) for ( var i = 0 ; i<3 ; i++){ (function (index){ setTimeout(function () { console.log(i) }, 0 ) })(i) } console.log(222)
輸出結果:
111
222
0
1
2
問題四:從閉包的角度給button等元素綁定事件demo
<a href="#" id="size-12">12</a> <a href="#" id="size-14">14</a> <a href="#" id="size-16">16</a>
function makeSizer(size) { return function() { document.body.style.fontSize = size + 'px'; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12; document.getElementById('size-14').onclick = size14; document.getElementById('size-16').onclick = size16;
size12
,size14
和 size16
三個函數將分別把 body
文本調整爲 12,14,16 像素。咱們能夠將它們分別添加到按鈕的點擊事件上。
總結:
上面是閉包的幾個典型例子,除此以外閉包常見的問題還有用閉包模擬私有方法等等,同時要注意開創閉包後要給它賦值爲null來清除,避免其常駐內存,形成內存泄漏等問題影響性能,固然還有其餘方式。
閉包考量性能,既實用,同時也有弊端。
運用好閉包是掌握JS的重點之一。革命還沒有成功,同志仍需努力!