看来减少遍历是没法解决事件系统性能问题了,那么现在只有从内存消耗考虑了。我常听人说C#很好用,对于web前端开发它就更好用了,我们可以直接在C#的IDE拖一个按钮到页面,按钮到了页面之后javascript代码会自动为该按钮添加个事件,当然里面的事件函数是个空函数,于是我想我们可以按这种方式在页面放置100个按钮,一个代码都不行就有了100个按钮事件处理,超级方便,最后我们对其中一个按钮添加具体的按钮事件,让页面跑起来,请问大家这个页面效率会高吗?在javascript里,每个函数都是一个对象,每个对象都会耗费内存,所以这无用的99个事件函数代码肯定消耗了很多宝贵的浏览器内存。当然现实开发环境里我们不会这么干的,但是在当今ajax流行,单页面开发疯狂普及的时代,一个网页上的事件都是超级多的,这就意味我们每个事件都有一个事件函数,但是我们每次操作都只会促发一个事件,此时其他事件都是躺着睡觉,起不到任何作用同时还要消耗计算机的内存。
我们需要一种方案改变这种情况,现实中的确有这种方案。为了清晰描述这个方案,我要先补充一些背景知识,在讲述DOM2事件处理里我提到了目标对象这个概念,抛开DOM2事件处理方式,在捕获事件处理和冒泡事件处理里也有目标对象的概念,目标对象就是事件具体操作的DOM元素,例如点击按钮操作里按钮就是目标对象,不管哪个事件处理方式,事件函数都会包含一个event对象,event对象有个属性target,target是永远指向目标对象的,event对象还有个属性就是currentTarget,这个属性指向的是捕获或冒泡事件流动到的DOM元素。由上文描述我们知道,不管是捕获事件还是冒泡事件,事件流都会流动到document上,假如我们在document上添加点击事件,页面上的按钮不添加点击事件,这时候我们点击按钮,我们知道document上的点击事件会促发,这里有个细节就是促发document点击事件时候,event的target的指向是button而不是document,那么我们可以这样写代码:
复制代码 代码如下:
<input type="button" value="BUTTON"/>
<a href="#">aa</a>
document.addEventListener("click",function(evt){
var target = evt.target;
switch(target.id){
case "btn":
alert("button");
break;
case "aa":
alert("a");
break;
}
},false);
运行之,我们发现效果和我们单独写按钮事件一样。但是它的好处是不言而喻的,一个函数搞定了整个页面的事件函数,而且没有事件函数被空闲,简直完美,这个方案还有个专业名称:事件委托。jQuery的delegate方法就是按这个原理做的。其实事件委托的效率不仅仅体现在事件函数的减少,它还能减少dom遍历操作,例如上面例子里我们在document上添加函数,document是页面里的顶层对象,读取它的效率是很高的,到了具体的对象事件我们也没有通过dom操作而是使用事件对象的target属性,所有这些只能用一句话概括:真是快,没理由的快。