Удаление анонимного прослушивателя событий

Есть ли способ удалить прослушиватель событий, добавленный следующим образом:

element.addEventListener(event, function(){/* do work here */}, false);

Без замены элемента?


person erikvold    schedule 24.06.2010    source источник
comment
Если существует более одного анонимного слушателя, как выбрать подходящего для удаления?   -  person Sean Hogan    schedule 24.06.2010
comment
@ Шон Хоган: что? Я не понимаю, как то, что вы спросили, связано с моим вопросом.   -  person erikvold    schedule 24.06.2010
comment
@Sean: Я думаю, что намеревались удалить прослушиватель событий из обработчика событий.   -  person icktoofay    schedule 24.06.2010


Ответы (11)


Невозможно полностью удалить обработчик событий, если вы не сохранили ссылку на обработчик событий при создании.

Обычно я добавляю их к основному объекту на этой странице, а затем вы можете выполнять итерацию и аккуратно избавляться от них, когда закончите с этим объектом.

person Joe    schedule 25.06.2010
comment
Интересно, почему addeventlistener не возвращает такую ​​ссылку для будущего использования removeeventlistener ... - person Michael; 27.08.2017
comment
Есть, это то, что вы экономите. - person Joe; 09.05.2018
comment
@Joe и для пользователей, опаздывающих сюда: addEventListener возвращает undefined по крайней мере в некоторых случаях. Например, в контексте BroadcastChannel. - person BairDev; 19.09.2018
comment
Обратите внимание, что согласно stackoverflow.com/a/27107765/377022 в консоли Chrome вы можете использовать функцию getEventListeners - person Jason Gross; 29.12.2018
comment
@JasonGross Да, API значительно улучшились с тех пор, как WebKit в 2010 году создал этот ответ. - person Joe; 08.01.2019
comment
@ Джо Конечно. Было бы неплохо обновить официально принятый ответ, чтобы люди, которые обращаются к нему как к справочнику в будущем (как и я), знали о новых разработках. - person Jason Gross; 08.01.2019
comment
Я не занимался обширной разработкой JavaScript около 5 лет. Я рад, что кто-то исправит его, чтобы он был правильным. Сейчас я больше работаю с серверной частью и встроенными приложениями, и я больше не использую современный JavaScript. Хотя в этой ссылке упоминается, что это доступно только в консоли, и запрос был на то, чтобы сделать это программно. Не знаю, изменилось ли это вообще. - person Joe; 08.01.2019

Вы можете удалить прослушиватель событий следующим образом:

element.addEventListener("click", function clicked() {
    element.removeEventListener("click", clicked, false);
}, false);
person icktoofay    schedule 24.06.2010
comment
Это работает только в том случае, если вы в первую очередь добавляете прослушиватель событий - вы можете изменить исходный код listener (). Поскольку это приложение Greasemonkey, это невозможно. Даже если сценарий базовой страницы был изменен, вы бы только добавили другого анонимного слушателя. - person Brock Adams; 24.06.2010
comment
@Brock: О, я думал, что намеревались удалить добавленного вами слушателя. Я не знаю, как удалить слушателя, который вы не добавляли и не имеет ссылки на функцию. - person icktoofay; 24.06.2010
comment
Брок прав, это вопрос для пользовательских сценариев, но, тем не менее, хороший ответ, я проголосовал за него! - person erikvold; 24.06.2010
comment
Вы можете добавить, что callee устарел с ES5 (см. mdn или ТАК) - person merours; 20.03.2015
comment
@fxm: Спасибо. Я не помню, почему я изначально использовал arguments.callee, а именованное выражение функции должно работать нормально, поэтому я отредактировал свой ответ. - person icktoofay; 23.03.2015

Анонимные привязанные прослушиватели событий

Самый простой способ удалить все прослушиватели событий для элемента - присвоить его outerHTML самому себе. Это отправляет строковое представление HTML через синтаксический анализатор HTML и назначает проанализированный HTML элемент. Поскольку JavaScript не передается, связанных прослушивателей событий не будет.

document.getElementById('demo').addEventListener('click', function(){
    alert('Clickrd');
    this.outerHTML = this.outerHTML;
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>


Анонимные делегированные прослушиватели событий

Единственное предостережение - это делегированные прослушиватели событий или прослушиватели событий в родительском элементе, которые отслеживают каждое событие, соответствующее набору критериев для его дочерних элементов. Единственный способ избежать этого - изменить элемент так, чтобы он не соответствовал критериям делегированного прослушивателя событий.

document.body.addEventListener('click', function(e){
    if(e.target.id === 'demo') {
        alert('Clickrd');
        e.target.id = 'omed';
    }
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>

person Community    schedule 27.09.2015

Старый вопрос, но вот решение.

Строго говоря, вы не можете удалить анонимного прослушивателя событий, если не сохраните ссылку на функцию. Поскольку цель использования анонимной функции, по-видимому, не заключается в создании новой переменной, вы можете вместо этого сохранить ссылку в самом элементе:

element.addEventListener('click',element.fn=function fn() {
    //  Event Code
}, false);

Позже, когда вы захотите удалить его, вы можете сделать следующее:

element.removeEventListener('click',element.fn, false);

Помните, что третий параметр (false) должен иметь то же значение, что и для добавления прослушивателя событий.

Однако сам вопрос напрашивается другой: почему?

Есть две причины использовать .addEventListener() вместо более простого .onsomething() метода:

Во-первых, он позволяет добавить несколько прослушивателей событий. Это становится проблемой, когда дело доходит до их выборочного удаления: вы, вероятно, в конечном итоге дадите им имена. Если вы хотите удалить их все, outerHTML решение от @ tidy -iant отлично подойдет.

Во-вторых, у вас есть возможность выбрать захват, а не пузырек события.

Если ни одна из причин не важна, вы можете решить использовать более простой onsomething метод.

person Manngo    schedule 08.07.2018
comment
Как это решение собираюсь использовать. Не могу понять, имеет это значение или нет, но после этого все равно будет ссылка на функцию, например. вызов element.fn () все равно вернет результат функции. Может ли это быть проблемой с памятью, если ее не очистить? - person Jarrod McGuire; 28.11.2018

Вы можете попробовать перезаписать element.addEventListener и делать все, что хотите.
Что-то вроде:

var orig = element.addEventListener;

element.addEventListener = function (type, listener) {
    if (/dontwant/.test(listener.toSource())) { // listener has something i dont want
        // do nothing
    } else {
        orig.apply(this, Array.prototype.slice.apply(arguments));
    }
};

ps: не рекомендуется, но поможет (не тестировал)

person w35l3y    schedule 26.04.2012
comment
В качестве альтернативы вы можете заменить EventTarget.prototype.addEventListener. Это сработало для меня - person Lorcan O'Neill; 26.01.2016

Назначить обработчики событий с помощью буквальных функций сложно - их не только невозможно удалить, не клонируя узел и не заменив его клоном - вы также можете непреднамеренно назначить один и тот же обработчик несколько раз, что не может произойти, если вы используете ссылка на обработчик. Две функции всегда рассматриваются как два разных объекта, даже если они идентичны по символам.

person kennebec    schedule 24.06.2010
comment
Вы не можете вкратце? что я считаю правильным ответом. - person erikvold; 24.06.2010
comment
Можно, если назначить их как свойства, а не использовать addEventListener. element.onmouseover = функция () {dothis}; element.onmouseover = ''; - person kennebec; 24.06.2010
comment
В приложениях Greasemonkey у нас нет никакого контроля над тем, как события создаются на базовой странице. К вашему сведению, в сценарии GM что-то вроде element.onmouseover=function все равно не будет работать из-за защиты песочницы. См. commons.oreilly.com/wiki/index.php / Greasemonkey_Hacks /. - person Brock Adams; 24.06.2010

Изменить: в соответствии с предложением Manngo для каждого комментария следует использовать .off () < / strong> вместо .unbind (), поскольку .unbind () устарел с jQuery 3.0 и заменен начиная с jQuery 1.7.

Несмотря на то, что это старый вопрос и в нем не упоминается jQuery, я опубликую здесь свой ответ, поскольку это первый результат для searchterm 'jquery remove anonymous event handler'.

Вы можете попробовать удалить его с помощью функции .off ().

$('#button1').click(function() {
       alert('This is a test');
});

$('#btnRemoveListener').click(function() {
       $('#button1').off('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button1">Click me</button>
<hr/>
<button id="btnRemoveListener">Remove listener</button>

Однако это работает, только если вы добавили слушателя с помощью jQuery, а не . addEventListener

Нашел это здесь.

person general64    schedule 11.03.2018
comment
Возвращаясь к вопросу, jQuery фактически сохраняет ссылку на функцию, а затем добавляет функцию. Вот почему вам не нужно указывать, какую функцию вы удаляете. То есть к моменту добавления он не анонимный. Кстати, jQuery предпочитает .off() .unbind(). - person Manngo; 07.07.2018
comment
зачем давать ответ jquery на вопрос JS? - person ortonomy; 12.05.2021

Если вы используете jQuery, попробуйте off метод

$("element").off("event");
person uingtea    schedule 03.10.2016

Метод jquery .off () удаляет обработчики событий, которые были прикреплены с помощью .on ()

person femi-adenubi    schedule 03.12.2017

С помощью спецификации языка ECMAScript2015 (ES2015, ES6) можно использовать эту nameAndSelfBind функцию, которая волшебным образом превращает анонимный обратный вызов в именованный и даже связывает его тело с собой, позволяя слушателю событий удалить себя изнутри, а также его для удаления из внешней области (JSFiddle):

(function()
{
  // an optional constant to store references to all named and bound functions:
  const arrayOfFormerlyAnonymousFunctions = [],
        removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout

  // this function both names argument function and makes it self-aware,
  // binding it to itself; useful e.g. for event listeners which then will be able
  // self-remove from within an anonymous functions they use as callbacks:
  function nameAndSelfBind(functionToNameAndSelfBind,
                           name = 'namedAndBoundFunction', // optional
                           outerScopeReference)            // optional
  {
    const functionAsObject = {
                                [name]()
                                {
                                  return binder(...arguments);
                                }
                             },
          namedAndBoundFunction = functionAsObject[name];

    // if no arbitrary-naming functionality is required, then the constants above are
    // not needed, and the following function should be just "var namedAndBoundFunction = ":
    var binder = function() 
    { 
      return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
    }

    // this optional functionality allows to assign the function to a outer scope variable
    // if can not be done otherwise; useful for example for the ability to remove event
    // listeners from the outer scope:
    if (typeof outerScopeReference !== 'undefined')
    {
      if (outerScopeReference instanceof Array)
      {
        outerScopeReference.push(namedAndBoundFunction);
      }
      else
      {
        outerScopeReference = namedAndBoundFunction;
      }
    }
    return namedAndBoundFunction;
  }

  // removeEventListener callback can not remove the listener if the callback is an anonymous
  // function, but thanks to the nameAndSelfBind function it is now possible; this listener
  // removes itself right after the first time being triggered:
  document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
  {
    e.target.removeEventListener('visibilitychange', this, false);
    console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
                '\n\nremoveEventListener 1 was called; if "this" value was correct, "'
                + e.type + '"" event will not listened to any more');
  }, undefined, arrayOfFormerlyAnonymousFunctions), false);

  // to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
  // name -- belong to different scopes and hence removing one does not mean removing another,
  // a different event listener is added:
  document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
  {
    console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
  }, undefined, arrayOfFormerlyAnonymousFunctions), false);

  // to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
  // formerly anonymous callback function of one of the event listeners, an attempt to remove
  // it is made:
  setTimeout(function(delay)
  {
    document.removeEventListener('visibilitychange',
             arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
             false);
    console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed;  if reference in '
                + 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
                + 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
  }, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();
person DDRRSS    schedule 02.03.2019

Следующее сработало для меня достаточно хорошо. Код обрабатывает случай, когда другое событие вызывает удаление слушателя из элемента. Предварительное объявление функций не требуется.

myElem.addEventListener("click", myFunc = function() { /*do stuff*/ });

/*things happen*/

myElem.removeEventListener("click", myFunc);
person Ice101781    schedule 25.03.2016
comment
Вы нарушили ограничения вопроса. - person Matthew Read; 27.09.2016