JavaScript中的匿名函数的removeEventListener

bit*_*kid 90 javascript safari anonymous-function dom-events

我有一个包含方法的对象.这些方法被放入匿名函数内的对象中.它看起来像这样:

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);
    };
});  
Run Code Online (Sandbox Code Playgroud)

(还有更多代码,但这足以显示问题)

现在我想在某些情况下停止事件监听器.因此我试图做一个removeEventListener,但我无法弄清楚如何做到这一点.我在其他问题中已经读过,无法在匿名函数上调用removeEventListener,但在这种情况下是否也是如此?

我在匿名函数中创建了一个方法,因此我认为这是可能的.看起来像这样:

t.disable = function() {
    window.document.removeEventListener("keydown", this, false);
}
Run Code Online (Sandbox Code Playgroud)

为什么我不能这样做?

还有其他(好的)方法吗?

奖金信息; 这只需要在Safari中工作,因此缺少即支持.

Ott*_*lla 93

如果你在实际函数中,可以使用arguments.callee作为函数的引用.如:

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

编辑: 如果您在严格模式下工作,这将无效("use strict";)

  • 给内联函数一个名称,你可以引用它而不需要使用arguments.callee:`button.addEventListener('click',function handler(){this.removeEventListener('click',handler);});` (17认同)
  • 正如Mozilla所述:"警告:第5版ECMAScript(ES5)禁止在严格模式下使用arguments.callee().​​避免使用arguments.callee()通过给函数表达式命名或使用函数声明函数必须自称." (4认同)
  • 在WinJS应用程序中尝试了这个,得到了下一个错误:"在严格模式下不允许访问参数对象的'callee'属性" (3认同)
  • 这很好,因为它保留了匿名函数的优点(不污染命名空间等)。 (2认同)

Ada*_*ath 65

我认为这是匿名函数的重点,它缺少一个名称或引用它的方法.

如果我是你,我只会创建一个命名函数,或者将它放在一个变量中,这样你就可以引用它.

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);
Run Code Online (Sandbox Code Playgroud)

然后你可以删除它

window.document.removeEventListener("keydown", handler);   
Run Code Online (Sandbox Code Playgroud)

  • 谢谢您的回复。我去了:var handler; window.document.addEventListener(“ keydown”,handler = function(e){但是我不明白为什么“ this”没有引用事件监听器。事件监听器不应该是一个对象吗? (2认同)
  • `this` 关键字可能会令人困惑。阅读它的好地方是 http://www.quirksmode.org/js/this.html (2认同)

Mel*_*lle 38

的一个版本奥托Nascarella,在严格的模式下工作的解决方案是:

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

  • 这可能不是正确的方法,但这是最简单的方法。 (3认同)
  • 美丽的方案! (2认同)
  • 我很好奇为什么这可能不是正确的方法 (2认同)

H K*_*H K 22

有一种新方法可以实现此目的,除 Safari 之外的大多数流行浏览器的最新版本都支持该方法。

检查caniuse以获得更新的支持。

更新:现在 Sefari(版本 15^)也支持。

我们可以添加一个选项来addEventListner调用signal并分配一个signalAbortController您可以稍后在其上调用该abort()方法。

这是一个例子。

我们创建一个AbortController

const controller = new AbortController();
Run Code Online (Sandbox Code Playgroud)

然后我们创建eventListner并传入选项signal

document.addEventListener('scroll',()=>{
    // do something
},{signal: controller.signal})
Run Code Online (Sandbox Code Playgroud)

然后为了eventListner稍后删除,我们调用:

controller.abort()
Run Code Online (Sandbox Code Playgroud)

  • 不知道这个,但这很酷!AbortController 最初用于取消 .fetch() 请求,可用于删除事件侦听器。https://css-tricks.com/using-abortcontroller-as-an-alternative-for-removing-event-listeners/ 还有一个用于 AbortController 的 ponyfill/polyfill:https://github.com/mo/abortcontroller- polyfill 这里还有一个更彻底的 polyfill https://github.com/mysticatea/event-target-shim (2认同)

shu*_*111 10

在现代浏览器中,您可以执行以下操作...

button.addEventListener( 'click', () => {
    alert( 'only once!' );
}, { once: true } );
Run Code Online (Sandbox Code Playgroud)

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


小智 7

window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));  
Run Code Online (Sandbox Code Playgroud)

可能是几个匿名函数,keydown [1]

  • `getEventListeners`似乎是Chrome Dev-tools的一部分,因此除了调试之外其他任何东西都不可用. (19认同)
  • 谢谢,你已经解决了一个谜团,至少在Chrome中,因为许多笑话者说这是不可能的.伙计,你就像......蝙蝠侠! (2认同)
  • 刚刚尝试了一下,确认它仅在开发工具中可用,而在包含在页面内的脚本中时则不可用。 (2认同)

小智 6

这并不理想,因为它删除了所有内容,但可能会满足您的需求:

\n
z = document.querySelector(\'video\');\nz.parentNode.replaceChild(z.cloneNode(1), z);\n
Run Code Online (Sandbox Code Playgroud)\n
\n

克隆节点会复制其所有属性及其值,包括固有的(在 xe2x80x93line 中)侦听器。它不会复制使用addEventListener() 添加的事件侦听器

\n
\n

Node.cloneNode()

\n

  • @MartinDawson我当然同意,但它对于某些情况可能很有用(例如由依赖项添加的未命名回调)。它也应该被记录下来,但它并没有说它不应该被使用。 (3认同)