>  기사  >  웹 프론트엔드  >  최고의 addEvent 이벤트 바인딩이 탄생한 방법_javascript 기술

최고의 addEvent 이벤트 바인딩이 탄생한 방법_javascript 기술

WBOY
WBOY원래의
2016-05-16 18:00:34961검색

상호 참조는 스크립트를 작성할 때 생성됩니다. 예를 들어 다음 코드는

코드 복사 코드는 다음과 같습니다.

window.onload = function () {
var x = document.getElementsByTagName('H3')
for (var i=0;i{
x[i].onclick = openClose;
x[i].관련Element = x[i].nextSibling; // 단순화된 상황
x[i].관련Element.관련Element = x[ i];
}
}

또는 스크립팅 언어에서 가장 일반적인 클로저를 함수에서 사용할 때 IE는 메모리를 회수할 수 없습니다. 닫힌 문장은 DOM 객체에 대한 이벤트 핸들러를 등록할 때 가장 일반적으로 사용됩니다. Novemberborn은 이 버그를 실행하고 실제로 느낄 수 있는 몇 가지 예를 제공합니다.
제가 가장 좋아하는 QuirkMode는 작년 초에 이 버그에 엄청난 위험이 숨겨져 있다는 사실을 깨달았습니다. 저는 웹 개발자들에게 이 문제에 주의를 기울이고 최선을 다해 노력할 것을 요청하여 모두를 격려하기 위해 자선 초대 대회를 열었습니다. 자체 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 )


John을 승자로 선택한 QuirkMode의 설명은 위 코드가 가장 간결하고 효과적이라는 점으로 요약할 수 있습니다. 메모리 문제를 피하면서도 this 키워드가 IE의 attachmentEvent에서 정상적으로 작동할 수 있도록 교묘하게 보장합니다. 물론 단점은 여전히 ​​존재합니다.

Netscape 4 및 Explorer 5 Mac은 지원되지 않습니다. (국내 프로그래머들이 비웃을 수도 있지만, 외국은 폭넓은 호환성을 강조함)
remove obj["e" type fn]는 RemoveEvent에서 생략됩니다.
간단히 말하면, 무슨 일이 있어도 단순한 승리입니다.
결과가 나오자마자 많은 참가자와 해설자들은 납득하지 못했으며 John의 코드에 대한 몇 가지 문제점을 빠르게 지적했습니다.

AddEvent 자체는 닫힌 문장을 사용하므로 IE의 문제를 근본적으로 해결하지는 않습니다. 메모리 누수 문제.
IE에서 동일한 유형의 이벤트가 반복적으로 등록되고 반복적으로 실행될 수 있는 문제는 해결되지 않습니다.
몇몇 전문가가 개선된 솔루션을 제안했습니다.


/*
John Resig의 독창적인 아이디어
Scott Andrew LePera, Dean Edwards 및 Peter-Paul Koch의 조정
Tino Zijdel의 IE용 수정(crisp)
IE에서는 다음을 참고하세요. 메모리 누수를 일으키고 여전히 W3C 이벤트 모델을 지원하는 브라우저에서와 동일하게 작동하지 않습니다.
- 이벤트 실행 순서가 동일하지 않습니다(FIFO에 대한 IE의 LIFO)
- 동일한 요소의 동일한 이벤트가 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 ;
}
}


물론 John 코드의 일부 단점이 수정되었습니다. 하지만 여전히 메모리 누수가 존재하고, 일부 브라우저에서는 이를 지원하지 않으며, IE의 반복 등록을 피할 수 없습니다. 또한, 댓글에 따르면, 동일한 객체에 여러 개의 이벤트 핸들러를 등록하면 IE와 다른 브라우저의 실행 순서가 달라지는데, 이는 또 다른 숨겨진 위험입니다.

며칠 후, 가장 엄격하다고 여겨지는 계획이 Dean Edwards에 의해 제안되었습니다. Dean의 솔루션은 다릅니다.

객체 감지를 수행하지 않음
addeventListener/attachEvent 메소드를 호출하지 않음
이 키워드를 올바른 컨텍스트에서 계속 실행
이벤트 객체 매개변수를 올바르게 전달
완전히 크로스 브라우저 (IE4 및 NS4 포함)
메모리 누수 없음
Dean의 코드는 다음과 같습니다:


코드 복사 코드는 다음과 같습니다.

// Dean Edwards 작성, 2005
// http://dean.edwards.name/function ;addEvent(element, type, handler) {
// 각 이벤트 핸들러에 고유 ID
// 이벤트 핸들러 함수에 대한 고유 값 설정
if (!handler.$$guid) handler.$$guid = addEvent.guid
// 이벤트 유형의 해시 테이블 생성; 요소
if (!element.events) element.events = {};
// 각 요소/이벤트 쌍에 대한 이벤트 핸들러의 해시 테이블 생성
var handlers = element.events[type] ;
if (!handlers) {
handlers = element.events[type] = {}
// 기존 이벤트 핸들러를 저장합니다(있는 경우).
// 객체가 다음과 같은 경우 이미 등록된 이벤트 핸들러가 있으면 유지하고 첫 번째 핸들러로 저장하세요.
if (element["on" type]) {
handlers[0] = element["on" type]
}
}
// 해시 테이블에 이벤트 핸들러 저장
handlers[handler.$$guid] = handler;
// 모든 작업을 수행하기 위한 전역 이벤트 핸들러 할당
// 반복 등록을 피하면서 통합 이벤트 처리를 위한 전역 함수 할당
element["on" type] = handlerEvent
}// 고유 ID를 생성하는 데 사용되는 카운터
addEvent; . guid = 1;function RemoveEvent(element, type, handler) {
// 해시 테이블에서 이벤트 핸들러 삭제
if (element.events && element.events[type]) {
delete element . events[type][handler.$$guid];
}
};function handlerEvent(event) {
// 이벤트 객체 가져오기(IE에서는 전역 이벤트 객체 사용)
event = event || window.event;
// 이벤트 핸들러의 해시 테이블에 대한 참조 가져오기
// 여기서는 handlerEvent 함수가 트리거되는 소스 요소로 변경됩니다.
var handlers = this.events[ event.type];
// 각 이벤트 핸들러 실행
for (var i in handlers) {
//이런 방식으로 작성하면 등록된 이벤트 핸들러 함수에서 이 항목이 올바르게 참조되고 직접 핸들러[ i]()가 작동하지 않습니다
this.$$handleEvent = handlers[i];
this.$$handleEvent(event)
}
}; >이 코드는 이전보다 훨씬 크지만 실제로는 매우 미묘합니다. 그러나 이 코드는 이벤트 핸들러 함수의 반환 값을 처리할 수 없거나 (Object.prototype)의 잘못된 적용으로 인해 for..in 루프가 중단될 수 있는 등의 다른 문제를 야기했습니다. 곧 Dean이 출시되었습니다. "업데이트된 버전"입니다.

최고가 되는 것은 정말 어렵습니다.

현재 Dean의 최종 버전이 가장 포괄적인 솔루션인 것 같습니다. 하지만 개인적인 생각으로는 좀 촌스럽다는 생각이 듭니다. 나는 항상 브라우저 자체 구현을 사용하고 단순함을 유지해야 한다고 주장합니다. 하지만 나는 아직도 외국인들의 엄격한 태도를 깊이 존경한다.
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.