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; } }
不执行对象检测(Object detection) 没有调用 addeventListener/attachEvent 方法 保持this关键字的运行于正确的上下文环境 正确传递 event 对象参数 完全跨浏览器至此(包括IE4和NS4) 不存在内存泄露 Dean的代码如下: 复制代码 代码如下: // written by Dean Edwards, 2005 // http://dean.edwards.name/function ;addEvent(element, type, handler) { // assign each event handler a unique ID // 为事件处理函数设定一个唯一值 if (!handler.$$guid) handler.$$guid = addEvent.guid++; // create a hash table of event types for the element if (!element.events) element.events = {}; // create a hash table of event handlers for each element/event pair var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // store the existing event handler (if there is one) // 如果对象已经注册有事件处理,那么要保留下来,并保存为第一个 if (element["on" + type]) { handlers[0] = element["on" + type]; } } // store the event handler in the hash table handlers[handler.$$guid] = handler; // assign a global event handler to do all the work // 指派一个全局函数做统一的事件处理,同时避免了反复注册 element["on" + type] = handleEvent; }; // a counter used to create unique IDs addEvent.guid = 1;function removeEvent(element, type, handler) { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } };function handleEvent(event) { // grab the event object (IE uses a global event object) event = event || window.event; // get a reference to the hash table of event handlers // 这里的 this 随 handlerEvent function 被触发的source element 变化而变化 var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { //这样写才能保证注册的事件处理函数中的 this 得到正确的引用,直接handlers[i]()是不行的 this.$$handleEvent = handlers[i]; this.$$handleEvent(event); } };