首页 > 语言 > JavaScript > 正文

最佳的addEvent事件绑定是怎样诞生的

2024-05-06 14:23:22
字体:
来源:转载
供稿:网友

当我们编写脚本的时候创建了交叉引用,例如如下代码:

window.onload = function() {  var x = document.getElementsByTagName('H3');  for (var i = 0; i < x.length; i++) {    x[i].onclick = openClose;    x[i].relatedElement = x[i].nextSibling; // simplified situation     x[i].relatedElement.relatedElement = x[i];  }}

或者在函数中使用脚本语言最常见的闭句Closures的时候,IE都无法回收内存。而闭句在给DOM对象注册事件处理器(event handler)的时候最为常用。Novemberborn提供了一些example可以让你运行并切实感受到这个bug。
我最喜爱的QuirkMode 去年初意识到这个bug存在巨大隐患,觉得有必要呼吁广大web开发者关注并竭力避免这个问题,于是举办了一个慈善邀请赛,鼓励大家提交各自 addEvent/removeEvent 方案。并终于在去年10月下旬宣布了他们认为的胜利者:John Resig,让John赢得胜利的代码如下:

function addEvent(obj, type, fn) {  if (obj.attachEvent) {    obj['e' + type + fn] = fn;    obj[type + fn] = function() {      obj['e' + type + fn](window.event);    }    obj.attachEvent('on' + type, obj[type + fn]);  } else obj.addEventListener(type, fn, false);}function removeEvent(obj, type, fn) {  if (obj.detachEvent) {    obj.detachEvent('on' + type, obj[type + fn]);    obj[type + fn] = null;  } else obj.removeEventListener(type, fn, false);}

QuirkMode 对选择John为胜利者的解释概括来说就是以上代码最简洁有效,在避免内存问题的同时还巧妙的保证了this关键字在ie的attachEvent中能正常工作。缺点当然还是存在:

不支持 Netscape 4 和 Explorer 5 Mac。(有可能国内的程序员会嗤之以鼻,但国外很强调广泛的兼容性)
在 removeEvent 中遗漏了remove obj["e"+type+fn]。
总之不管怎么说,简单取胜。
结果一出,众多参赛与评论者不服气,很快又挑出了John的代码的几处毛病:

addEvent中本身就使用了闭句,所以没有根本解决IE内存泄露的问题。
没有解决同类型的事件可能被重复注册而被IE重复执行的问题。
几个高手于是提出了改进性的方案:

/* Original idea by John Resig Tweaked by Scott Andrew LePera, Dean Edwards and Peter-Paul Koch Fixed for IE by Tino Zijdel (crisp) Note that in IE this will cause memory leaks and still doesn't quite function the same as in browsers that do support the W3C event model: - event execution order is not the same (LIFO in IE against FIFO) - functions attached to the same event on the same element multiple times will also get executed multiple times in IE */function addEvent(obj, type, fn) {  if (obj.addEventListener) obj.addEventListener(type, fn, false);  else if (obj.attachEvent) {    obj["e" + type + fn] = fn;    obj.attachEvent("on" + type,    function() {      obj["e" + type + fn]();    });  }}function removeEvent(obj, type, fn) {  if (obj.removeEventListener) obj.removeEventListener(type, fn, false);  else if (obj.detachEvent) {    obj.detachEvent("on" + type, obj["e" + type + fn]);    obj["e" + type + fn] = null;  }}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选