JavaScript의 익명 함수에 대한 removeEventListener


101

메서드가있는 개체가 있습니다. 이러한 메서드는 익명 함수 내부의 개체에 배치됩니다. 다음과 같이 보입니다.

var t = {};
window.document.addEventListener("keydown", function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
});  

(더 많은 코드가 있지만 문제를 보여주기에는 충분합니다)

이제 경우에 따라 이벤트 리스너를 중지하고 싶습니다. 따라서 removeEventListener를 시도하고 있지만 어떻게해야할지 알 수 없습니다. 익명 함수에서 removeEventListener를 호출 할 수 없다는 다른 질문을 읽었지만이 상황에서도 마찬가지입니까?

익명 함수 내부에 생성 된 메서드가 있으므로 가능하다고 생각했습니다. 다음과 같이 보입니다.

t.disable = function() {
    window.document.removeEventListener("keydown", this, false);
}

왜 이렇게 할 수 없습니까?

이 작업을 수행하는 다른 (좋은) 방법이 있습니까?

보너스 정보; 이것은 Safari에서만 작동하므로 IE 지원이 누락되었습니다.


이 기능을 저장하지 않는 이유는 무엇입니까? 이벤트 처리기는 익명 함수가 아닐 수 있습니다.
kirilloid

2
조금 늦었 음을 알고 있지만 Node.setUserData /Node.getUserData 메서드를 사용하여 요소에 대한 데이터를 저장할 수도 있습니다 . 예를 들어, anon 리스너를 설정해야하는 경우 (제거 할 수 있어야 함) 먼저 userdata를 anon 함수로 설정 (Elem.setUserData('eventListener', function(e){console.log('Event fired.');}, null);한 다음 Elem.addEventListener ( 'event', Elem.getUserData ( 'eventListener'), false); ... 그리고 removeEventListener도 마찬가지입니다. 당신이 이것을 잘 볼 수 있기를 바랍니다.
Chase

편집 : 이전 의견에 따르면 Firefox에서만 작동한다고 생각합니다 ... IE8 (IE9 알 수 없음), Safari 5.1.2, Chrome (?), Opera 11 .. 주사위 없음
Chase

답변:


76

나는 그것이 익명의 기능의 요점이라고 믿으며 이름이나 참조 방법이 부족합니다.

내가 당신이라면 명명 된 함수를 만들거나 변수에 넣어서 참조 할 수 있습니다.

var t = {};
var handler = function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
};
window.document.addEventListener("keydown", handler);

그런 다음 제거 할 수 있습니다.

window.document.removeEventListener("keydown", handler);   

3
당신의 답변에 감사드립니다. 나는 함께 갔다 : var handler; window.document.addEventListener ( "keydown", handler = function (e) {하지만 내가 이해하지 못하는 것은 "this"가 이벤트 리스너를 참조하지 않는 이유입니다. 이벤트 리스너가 객체가 아니어야합니까?
bitkid

1
this키워드는 혼동 될 수있다. 읽기 좋은 곳은 quirksmode.org/js/this.html입니다
Adam Heath

대단히 감사합니다. 이것은 가장 도움이되었습니다.
bitkid

나는 웹 사이트에서 정말로 지속적인 광고를 차단하기 위해 이것을 시도하고있다. 이것이 익명 함수의 요점이라는 것을 알고 있지만, 이것이 내가 그렇게하는 방법을 알고 싶지 않다는 의미는 아닙니다.
Wyatt8740

@bitkid : 핸들러 함수 (화살표 함수가 아니라고 가정) 내에서는 this이벤트 자체 (매개 변수 e) 가 아니라 리스너가 추가되는 요소를 나타냅니다 . 따라서 this === e.currentTarget. developer.mozilla.org/en-US/docs/Web/API/EventTarget/…
chharvey

100

실제 함수 내부에 있으면 arguments.callee를 함수에 대한 참조로 사용할 수 있습니다. 다음과 같이 :

button.addEventListener('click', function() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', arguments.callee);
});

편집 : 엄격 모드 ( "use strict";) 에서 작업하는 경우 작동하지 않습니다.


2
이것은 익명 함수의 장점을 보존하기 때문에 좋습니다 (네임 스페이스 등을 오염시키지 않음).
bompf 2012 년

3
, WinJS 응용 프로그램이 시도 다음 오류가 발생했습니다 : "는 인수 객체의 '수신자'속성 액세스가 엄격 모드에서 사용할 수 없습니다"
발렌틴 캔터

1
@ValentinKantor : 코드에 "엄격한 사용"이 있기 때문입니다. 성명, 엄격한 모드에서 호출 수신자를 사용할 수 없습니다.
OMA

19
인라인 함수에 이름을 지정하면 arguments.callee에 의존하지 않고 참조 할 수 있습니다.button.addEventListener('click', function handler() { this.removeEventListener('click', handler); });
Harry Love

4
Mozilla에 언급 된대로 : "경고 : ECMAScript (ES5) 5 판은 엄격 모드에서 arguments.callee () 사용을 금지합니다. 함수 표현식에 이름을 지정하거나 함수 선언을 사용하여 arguments.callee () 사용을 피하십시오. 스스로를 불러야합니다. "
친구

50

Strict 모드에서 작동하는 Otto Nascarella 솔루션 의 버전 은 다음과 같습니다.

button.addEventListener('click', function handler() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', handler);
});

4
아름다운 솔루션!
Eric Norcross

2
이것은 올바른 방법이 아닐 수도 있지만 이것이 가장 쉬운 방법입니다.
Vignesh

7
window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));  

여러 익명 기능이 될 수 있습니다, keydown 1

경고 : 코드에서만 작동 Chrome Dev Tools하며 코드에서 사용할 수 없습니다 : 링크


2
감사합니다. 적어도 Chrome에서는 많은 조커들이 불가능하다고 말한 수수께끼를 풀었습니다. 이봐, 당신은 마치 ... 배트맨!
JasonXA

20
getEventListenersChrome Dev-tools의 일부인 것처럼 보이므로 실제로 디버깅 이외의 용도로 사용할 수 없습니다.
DBS

1
방금 시도한 결과 페이지 내의 스크립트에 포함될 때가 아니라 Devtools에서만 사용할 수 있음을 확인했습니다.
Andres Riofrio

5

최신 브라우저에서는 다음을 수행 할 수 있습니다.

button.addEventListener( 'click', () => {
    alert( 'only once!' );
}, { once: true } );

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters


IE 또는 edge <16 버전이 실제로이 기능을 지원하지 않는다는 사실을 알게 될 때까지 식히십시오. IE는 더 이상 사용되지 않고 Edge가 대신 할 것이며 자체 "EdgeHTML"대신 웹킷 엔진을 사용할 것이므로 적어도 5 년 후에는이를 사용할 수 있습니다.
SidOfc

1
DOM 레벨 4 항목에 대한이 polyfill을 사용하면 괜찮습니다. npmjs.com/package/dom4
shunryu111

2

익명이 아닌 옵션

element.funky = function() {
    console.log("Click!");
};
element.funky.type = "click";
element.funky.capt = false;
element.addEventListener(element.funky.type, element.funky, element.funky.capt);
// blah blah blah
element.removeEventListener(element.funky.type, element.funky, element.funky.capt);

Andy 로부터 피드백받은 이후 ( 아주 맞지만 많은 예에서와 같이 아이디어의 맥락 적 확장을 보여주고 싶었습니다 ), 여기에 덜 복잡한 설명이 있습니다.

<script id="konami" type="text/javascript" async>
    var konami = {
        ptrn: "38,38,40,40,37,39,37,39,66,65",
        kl: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
    };
    document.body.addEventListener( "keyup", function knm ( evt ) {
        konami.kl = konami.kl.slice( -9 );
        konami.kl.push( evt.keyCode );
        if ( konami.ptrn === konami.kl.join() ) {
            evt.target.removeEventListener( "keyup", knm, false );

            /* Although at this point we wish to remove a listener
               we could easily have had multiple "keyup" listeners
               each triggering different functions, so we MUST
               say which function we no longer wish to trigger
               rather than which listener we wish to remove.

               Normal scoping will apply to where we can mention this function
               and thus, where we can remove the listener set to trigger it. */

            document.body.classList.add( "konami" );
        }
    }, false );
    document.body.removeChild( document.getElementById( "konami" ) );
</script>

이것은 효과적으로 익명의 함수 구조를 허용하고 실질적으로 사용되지 않는 callee의 사용을 하며 쉽게 제거 할 수 있습니다.

덧붙여 즉시 리스너를 설정 한 후 스크립트 요소의 제거는 (선호하는 코드를 숨기는 귀여운 트릭 캐고 눈에 굳어 지 분명하지 않았다이다 놀라움을 망칠 것 ;-)

따라서 방법 ( 보다 간단하게 )은 다음과 같습니다.

element.addEventListener( action, function name () {
    doSomething();
    element.removeEventListener( action, name, capture );
}, capture );

2
이것은 너무 복잡합니다.
Ben Sinclair 2014 년

@Andy 동의합니다.하지만 익명의 기능을 제거 할 방법이 없다는 것을 보여 주려고했습니다. 그것은이 있어야합니다 어떤 방법으로 참조 할 (심지어 수신자가 (나쁜 M'Kay)의 기능을 참조하는), 따라서 제공하는 하나의 (다른) 방법의 예를 함수가 참조 할 수 있습니다 -이 부분으로 구축하는 방법, 그리고 나중에 참조 할 수 있도록 똑같이 저장할 수 있습니다 (중요한 부분). 분명히 진정한 익명 함수는 즉석에서 빌드되므로 나중에 어떤 이벤트 작업 / 유형과 캡처가 사용되었는지 여부도 알고 있어야합니다. 어쨌든, 여기에 더 나은 방법은 :-)입니다
프레드 Gandt

나를 위해 완벽하게 작동했습니다. 익명이 될 수 없기 때문에 함수에 인수를 전달하는 다른 방법을 볼 수 없었습니다.
nicodemus13 2014 년

2

이것은 모든 것을 제거하므로 이상적이지는 않지만 필요에 따라 작동 할 수 있습니다.

z = document.querySelector('video');
z.parentNode.replaceChild(z.cloneNode(1), z);

노드를 복제하면 내장 (인라인) 리스너를 포함하여 모든 속성과 해당 값이 복사됩니다. addEventListener ()를 사용하여 추가 된 이벤트 리스너는 복사하지 않습니다.

Node.cloneNode ()


이것은 절대적으로 훌륭합니다
아마드 Alfy

1

자바 스크립트 : addEventListener 메서드는 호출 된 EventTarget (Element | document | Window)에 지정된 리스너를 등록합니다.

EventTarget. addEventListener ( event_type , handler_function, Bubbling | Capturing );

마우스, 키보드 이벤트 WebConsole의 예제 테스트 :

var keyboard = function(e) {
    console.log('Key_Down Code : ' + e.keyCode);
};
var mouseSimple = function(e) {
    var element = e.srcElement || e.target;
    var tagName = element.tagName || element.relatedTarget;
    console.log('Mouse Over TagName : ' + tagName);    
};
var  mouseComplex = function(e) {
    console.log('Mouse Click Code : ' + e.button);
} 

window.document.addEventListener('keydown',   keyboard,      false);
window.document.addEventListener('mouseover', mouseSimple,   false);
window.document.addEventListener('click',     mouseComplex,  false);

removeEventListener 메서드는 EventTarget.addEventListener ()로 이전에 등록 된 이벤트 리스너를 제거합니다.

window.document.removeEventListener('keydown',   keyboard,     false);
window.document.removeEventListener('mouseover', mouseSimple,  false);
window.document.removeEventListener('click',     mouseComplex, false);

사용해도 되나요


1

이에 대한 최신 접근 방식을 제공하려면 :

//one-time fire
element.addEventListener('mousedown', {
  handleEvent: function (evt) {
    element.removeEventListener(evt.type, this, false);
  }
}, false);

2
설명이 좋을 것입니다.
Poul Bak

1

나는 같은 문제를 우연히 발견했으며 이것이 내가 얻을 수있는 최고의 해결책이었습니다.

/*Adding the event listener (the 'mousemove' event, in this specific case)*/
element.onmousemove = function(event) {
    /*do your stuff*/
};
/*Removing the event listener*/
element.onmousemove = null;

window요소와 'mousemove'이벤트에 대해서만 이것을 테스트 했으므로이 접근 방식에 몇 가지 문제가있을 수 있습니다.


0

당신이 요구하는 것과 관련하여 아마도 최상의 솔루션이 아닐 수 있습니다. 이벤트 리스너 호출로 인라인으로 선언 된 익명 함수를 제거하는 효율적인 방법을 아직 결정하지 못했습니다.

개인적으로 변수를 사용 <target>하여 이벤트 리스너 호출 외부에 함수 를 저장 하고 선언합니다. 예 :

const target = document.querySelector('<identifier>');

function myFunc(event) { function code; }

target.addEventListener('click', myFunc);

그런 다음 리스너를 제거하려면 :

target.removeEventListener('click', myFunc);

받을 수있는 최고의 권장 사항은 아니지만 익명 함수를 제거하는 데 유용한 유일한 해결책은 HTML 요소를 제거한 다음 교체하는 것입니다. 더 나은 바닐라 JS 방법이 있어야한다고 확신하지만 아직 보지 못했습니다.


0

나는 이것이 상당히 오래된 스레드라는 것을 알고 있지만 유용하다고 생각하는 사람들을 위해 2 센트를 넣을 것이라고 생각했습니다.

스크립트 (창의적이지 않은 메소드 이름에 대한 사과) :

window.Listener = {
    _Active: [],
    remove: function(attached, on, callback, capture){
        for(var i = 0; i < this._Active.length; i++){
            var current = this._Active[i];
            if(current[0] === attached && current[1] === on && current[2] === callback){
                attached.removeEventListener(on, callback, (capture || false));
                return this._Active.splice(i, 1);
            }
        }
    }, removeAtIndex(i){
        if(this._Active[i]){
            var remove = this._Active[i];
            var attached = remove[0], on = remove[1], callback = remove[2];
            attached.removeEventListener(on, callback, false);
            return this._Active.splice(i, 1);
        }
    }, purge: function(){
        for(var i = 0; i < this._Active.length; i++){
            var current = this._Active[i];
            current[0].removeEventListener(current[1], current[2]);
            this._Active.splice(i, 1);
        }
    }, declare: function(attached, on, callback, capture){
        attached.addEventListener(on, callback, (capture || false));
        if(this._Active.push([attached, on, callback])){
            return this._Active.length - 1;
        }
    }
};

다음과 같이 사용할 수 있습니다.

// declare a new onclick listener attached to the document
var clickListener = Listener.declare(document, "click" function(e){
    // on click, remove the listener and log the clicked element
    console.log(e.target);
    Listener.removeAtIndex(clickListener);
});

// completely remove all active listeners 
// (at least, ones declared via the Listener object)
Listener.purge();

// works exactly like removeEventListener
Listener.remove(element, on, callback);

-4
window.document.onkeydown = function(){};

= 정의되지 않은 이유는 무엇입니까? 진짜 나쁜 놈.
Ben Sinclair 2014 년

2
에 등록 된 핸들러는 제거되지 않습니다 addEventListener.
Luc125
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.