阅读以下JavaScript代码:
if (window.addEventListener) {
var addListener = function(el, type,listener, useCapture) {
el.addEventListener(type, listener,useCapture);
};
} else if (document.all) {
addListener = function(el, type,listener) {
el.attachEvent("on" +type, function() {
listener.apply(el);
});
};
}
请阐述
a) 代码的功能;
b) 代码的优点和缺点;
c) listener.apply(el) 在此处的作用;
d) 如果有可改进之处,请给出改进后的代码,并说明理由
答:
a)注册事件。
扩展:事件注册方式有两种:一种是对事件目标对象或文档元素设置属性,另一种是将事件处理程序传递给对象或元素。每一种技术都有两个版本。
第一种:1、可以在javascript中设置事件处理程序对象的属性。2、在HTML中直接设置相应的属性。例如:
window.οnlοad=function(){.....}
或者
<button οnclick="alert('Thank you')">click me</button>
事件处理程序属性的名字有“on”后面跟着事件名组成的:onclick、onchange、onload、onmousemove等。
第二种:1、addEventListener/removeEventListener。2、attachEvent/detachEvent.。
第二种比第一种有个好处,就是可以为同一个对象的同一个事件类型注册多个处理函数。以addEventListener为例,代码如下:
<button id="mybutton">clcik me</button>
<script>
var b=document.getElementById("mybutton");
b.οnclick=function(){alert("event1");}//第一类注册事件
b.addEventListener("click",function(){alert("event2")},false);//第二类注册事件
</script>
当点击button按钮时,他会按照注册顺序先弹出event1再弹出event2.
attachEvent和addEventListenter功能一样,就是针对的版本不同而已。addEventListenter是在除IE8和IE8之前版本的所有浏览器(FF,Chrom。。。。)。而attachEvent是IE5~IE8这几个版本。与addEventListenter不同。因为IE事件模型不支持事件捕获,所以attachEvent/detachEvent只有两个参数;要给attachEvent传递“on”+“事件名”;调用的次序可能与注册的次序不一样。
因此,为了事件浏览器兼容问题,通常采用题目中给的注册方式。但是仍存在一些问题。
b)优点:跨浏览器,特性探测。缺点:document.all。
扩展:doument.all是浏览器是否是IE.document.all返回的是一个对象数组,代表这个页面内的所有元素。是IE4.0+的专有属性。
if(document.all)
alert("is IE!");
因此,这段代码的缺点是document.all
c)使IE中的Listner的this是el,与其他浏览器一致。
扩展:attachEvent注册事件程序作为调用函数时,它们的this值是全局Window对象。所以可以通过函数的间接调用解决。函数的间接调用有两种方式:call和apply。Javascript权威指南第455页,用的是call方法。
call方法和apply方法的第一个实参都是要调用函数的母对象,在函数体内用this来获得对它的引用。
对于call来说,第二个实参就是要传入待调用函数的值,比如,以对象o的方法的形式调用函数f(),并传入两个参数,call和apply方法不同。可以使用这样的代码:
f.call(o,1,2); //
f.apply(o,[1,2])//
f.apply(o,array_of_numbers)//array_of_numbers代表一个数组
从代码来看apply的实参放入了一个数组中。从第三个来看apply可以是一个任意长度的数组,因此,我们可以看出apply方法的灵活性较大。
d)document.all改成window.attachEvent;useCapture的默认值.
Javascript权威指南第455页代码:
function addEvent(target,type,handler){
if(target.addEventListener)
target.addEventListener(type,handler,false);
else if(target.attachEvent)
target.attachEvent("on"+type,function(event){handler.call(target,event);});
}
好了,再看看上面代码,其实个人认为既然注册事件的第一种方法试用于各个浏览器,我们为什么不能再添加一个else呢
else
target["on"+type]=handler;