事件捕獲、事件冒泡、事件委託,這三個類似又不盡相同的術語把我搞懵了很長一段時間,今天專門抽時間挨個看了一遍。設計模式
首先,是那個聞名遐邇的圖瀏覽器
事件捕獲和事件冒泡是事件流機制層面的東西,不以代碼的意志爲轉移。函數
DOM2級規範(瀏覽器自身的事件規範)要求事件應該從document對象開始向下傳播,找到具體的目標前,整個過程都是捕獲階段。性能
找到具體的目標後,開始向外層冒泡,直到回到document對象結束,這個過程叫冒泡階段。spa
但規範只是規範,較舊的瀏覽器都是從window對象開始捕獲事件的,建議放心地使用事件冒泡,特殊狀況下再考慮事件捕獲。設計
接下來是事件委託,這個纔是重點!code
JS和HTML之間是靠事件來實現交互的,若是有多個div須要綁定click事件監聽,不管是DOM0級和DOM2級,添加到頁面上的事件處理程序數量將直接關係到頁面的總體性能。對象
事件委託就是解決性能問題的,你能夠把它看作是一種解決方案或設計模式。blog
事件委託利用了事件冒泡,只指定一個事件處理程序,就能夠管理某一類型的全部事件。事件
少廢話,上代碼(如下例子來自《Javascript高級程序設計》,略刪改)
// 面對這樣一段HTML <ul id="myLinks"> <li id="goSomewhere"></li> <li id="doSomething"></li> <li id="sayHi"></li> </ul>
不使用事件委託的笨辦法:
var item1 = document.getElementById('goSomewhere') var item2 = document.getElementById('doSomething') var item3 = document.getElementById('sayHi') item1.addEventListener('click', function(e) { }, false) item2.addEventListener('click', function(e) { }, false) item3.addEventListener('click', function(e) { }, false)
使用事件委託,對於用戶來講最終的結果相同,但咱們其實只取了一個DOM元素,只添加了一個事件處理程序,但這種實現方案所須要佔用的內存更少。
var list = document.getElementById('myLinks') list.addEventListener('click', function(e) { var target = e.target; switch(target.id) { case 'goSomewhere': // TODO break; case 'doSomething': // TODO break; case 'sayHi': // TODO break; } }, false)
若是可行的話,能夠考慮爲document對象添加一個事件處理程序,優勢以下:
關於上面三點的最後一點,解釋一下:若是咱們沒有使用事件委託,那在具體元素好比某div上添加的監聽,在該div被移除出DOM樹後,綁在它身上的事件處理程序可能沒法被垃圾回收,形成浪費。
每當將事件處理程序指定給元素時,運行中的瀏覽器代碼與支持頁面交互的JS代碼之間會創建一個鏈接,這種鏈接越多,頁面執行效率越低,利用事件委託能夠儘量減小這種鏈接數量。呃……雖然可能也無法成功垃圾回收,但總體性能仍是更高的。