面試的時候有點蒙,結束以後想一想本身好像根本就誤解了面試官的問題,由於我理解的這個問題自己就沒有意義。可是當時已經有一些思路,可是在一個點上被卡住。面試
結束以後腦子瞬間靈光,想出了當時沒有邁出的那一小步。因此不想計較這個問題自己的意義,單純的想要把這個我理解錯了的問題解決,就當是知足本身一個小小的願望吧。數組
用addEventListener()和attachEvent()給一個DOM元素綁定事件處理程序時,若是傳入一個匿名函數,那麼用相應的removeEventListener()和detachEvent()是沒法將這個匿名的處理程序解除綁定的。因此咱們用的時候應該傳入一個函數表達式。函數
那麼,若是我就是想使用匿名函數進行綁定和解綁,怎麼解決?this
既然這兩個函數都高冷的說明了不接受相同的匿名函數進行解綁,那麼就只能另尋出路,不能靠它來管理事件了。spa
因此須要一個自定義的對象來管理事件。prototype
事件處理程序的本質就是,當一個事件在一個對象上發生時,執行監聽這個事件的函數。翻譯
翻譯一下:code
一個DOM元素可能被綁定多個事件類型的處理程序。好比click的時候顏色改變,mouseover的時候變大。對象
一個事件類型可能綁定多個事件處理程序。好比mouseover的時候又變色又變大。blog
因此,這個事件對象應該有一個屬性用來存儲這個DOM元素上綁定的全部事件處理程序,還應該有兩個方法,一個用來添加,一個用來刪除。
{ handlers:{ type1:[handler1,handler2], type2:[handler1,handler2], ...//其餘事件類型和對應的事件處理函數 }, on:function(){}, off:function(){} }
當一個事件發生時,就調用這個對象裏面對應的事件類型的數組裏面的全部函數。
因此綁定事件就是往對應的數組裏面添加函數,解除綁定事件就是把這個函數從這個數組裏面刪掉。
那麼怎麼保證操做的是那個正確的DOM元素呢?
顯然,每一個DOM元素都應該須要一個這樣的對象,用於管理本身的事件處理程序。
每一個對象都有的東西,那不就是他的屬性嘛。(而我當時就被卡在了這裏)。
每一個DOM元素都須要這樣一個對象,並且每一個對象中的on()和off()方法都是相同的,因此須要一個構造函數,把這兩個方法放到他的原型對象中去。
function EventManage(){ this.handlers={} } EventManage.prototype={ on:function(type,handler){ if(!this.handlers[type]){ this.handlers[type]=[handler]; return true; //避免添加多個事件 }else{ this.handlers[type].push(handler); } }, off:function(type,handler){ for(var i=0,len=this.handlers[type].length;i<len;i++){ if(this.handlers[type][i].toString()==handler.toString()){ this.handlers[type].splice(i,1); } } } }
每一個對象有了這兩個方法,就能夠自行添加和移除事件處理程序了,可是,監聽事件,仍是要靠JavaScript提供的方法,因此借用addEventListner()和attachEvent()來監聽事件:
var EventUtil={}; EventUtil.on=function(ele,type,handler){ if (!ele.event) { ele.event=new EventManage(); } var isNewType=ele.event.on(type,handler); var fire=function(){ for(var i=0,len=ele.event.handlers[type].length;i<len;i++){ ele.event.handlers[type][i](); } }; if (isNewType) { if (ele.addEventListener) { ele.addEventListener(type,fire,false); }else{ ele.attachEvent("on"+type,fire); } } } EventUtil.off=function(ele,type,handler){ ele.event.off(type,handler); }
這裏要注意一個問題,每次使用EventUtil.on()時都會從新定義一個fire函數,addEventListener()就會給相同的事件類型添加多個相同的事件處理程序,因此須要判斷一下這個事件類型是否是新增的,若是是的話再用addEventListener()來監聽這個事件類型。
var btn=document.getElementById("btn"); EventUtil.on(btn,"click",function(){ console.log("11"); }); EventUtil.on(btn,"click",function(){ console.log("22"); }); EventUtil.off(btn,"click",function(){ console.log("11"); });
當點擊btn時,只打印了"22",說明匿名函數成功解綁。