Home  >  Article  >  Web Front-end  >  How the best addEvent event binding was born_javascript skills

How the best addEvent event binding was born_javascript skills

WBOY
WBOYOriginal
2016-05-16 18:00:34991browse

Cross-references are created when we write scripts, for example the following code:

Copy the code The code is as follows:

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

Or when using Closures, the most common closures in scripting languages, in functions, IE cannot reclaim memory. Closed sentences are most commonly used when registering event handlers for DOM objects. Novemberborn provides some examples that allow you to run and actually feel this bug.
My favorite QuirkMode realized that this bug had huge hidden dangers early last year. I felt it was necessary to call on web developers to pay attention and try their best to avoid this problem, so I held a charity invitational competition to encourage everyone to submit their own addEvent/removeEvent solutions. And finally announced the winner they considered in late October last year: John Resig. The code that allowed John to win was as follows:
Copy code The code is as follows:

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’s explanation for choosing John as the winner can be summarized as the above code is the most concise and effective. While avoiding memory problems, it also cleverly ensures that the this keyword can work normally in IE’s attachEvent. Disadvantages of course still exist:

Netscape 4 and Explorer 5 Mac are not supported. (It is possible that domestic programmers will sneer, but foreign countries emphasize broad compatibility)
remove obj["e" type fn] is omitted in removeEvent.
In short, no matter what, simple wins.
As soon as the results came out, many contestants and commentators were unconvinced, and quickly pointed out several problems with John's code:

AddEvent itself uses closed sentences, so it does not fundamentally solve the problem of IE memory Leakage issue.
It does not solve the problem that the same type of events may be repeatedly registered and executed repeatedly by IE.
A few experts then proposed an improved solution:
Copy the code The code is as follows:

/*
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 ;
}
}

Obviously, although some shortcomings of John's code have been corrected. However, memory leaks still exist, some browsers still do not support it, and repeated registration of IE cannot be avoided. In addition, according to the comments: When multiple event handlers are registered on the same object, the execution order of IE and other browsers is different, which is another hidden danger.

A few days later, a plan considered to be the most rigorous was proposed by Dean Edwards. Dean’s solution is different:

Does not perform object detection
Does not call addeventListener/attachEvent method
Keeps this keyword running in the correct context
Passes it correctly event object parameters
Completely cross-browser so far (including IE4 and NS4)
No memory leaks
Dean’s code is as follows:
Copy code The code is as follows:

// written by Dean Edwards, 2005
// http://dean.edwards.name/function ;addEvent(element, type, handler) {
// assign each event handler a unique ID
// Set a unique value for the event handler function
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 the object is already registered If there is an event handler, keep it and save it as the first 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
// Assign a global function for unified event processing, while avoiding repeated registration
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 here changes with the source element where the handlerEvent function is triggered
var handlers = this.events[ event.type];
// execute each event handler
for (var i in handlers) {
//Writing in this way ensures that this in the registered event handler function is correctly referenced, directly handlers[ i]() does not work
this.$$handleEvent = handlers[i];
this.$$handleEvent(event);
}
};

This code is much larger than before, but it is indeed very subtle. However, this code introduced other problems, such as the inability to handle the return value of the event handler function, the for..in loop may be interrupted due to incorrect application of (Object.prototype), etc... Soon Dean launched an "updated version".

It’s really hard to be the best.

Currently it seems that Dean's final version is the most comprehensive solution. But in my personal opinion, I feel that it is a bit nit-picky. I always insist on using the browser's own implementation and keeping it simple. But I still deeply admire the rigorous attitude of foreigners.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn