如何有效移除绑定了额外参数的事件监听器?
如何有效移除用bind绑定的事件监听器?
问题核心原因
这个坑我之前踩过!问题出在**bind()每次调用都会返回一个全新的函数实例**——你添加监听器时,给每个word生成了一个绑定后的专属函数;但移除时又重新调用bind()生成了新的函数,这两个函数的引用完全不一样,浏览器根本找不到要移除的那个监听器,所以代码执行了也没效果。
解决方案:提前存储绑定后的函数引用
我们需要把每个word对应的绑定函数保存下来,确保移除时用的是和添加时完全相同的函数引用。这里有两种常用的实现方式:
方式1:用数组统一存储绑定函数
// 先声明一个数组,专门存每个word对应的绑定函数 const boundKeyHandlers = []; // 添加监听器时,把绑定后的函数存进数组 words.forEach(word => { const boundHandler = eventHandler.bind(null, word); boundKeyHandlers.push({ word, handler: boundHandler }); window.addEventListener("keypress", boundHandler); }); // 移除监听器时,遍历数组用存储的引用移除 const removeIT = () => { boundKeyHandlers.forEach(({ handler }) => { window.removeEventListener("keypress", handler); }); // 清空数组,避免后续重复操作 boundKeyHandlers.length = 0; }
方式2:把绑定函数存在DOM元素的自定义属性上
如果不想额外维护数组,可以直接把绑定函数挂在对应的word元素上:
// 添加监听器时,将绑定函数存到word的自定义属性中 words.forEach(word => { const boundHandler = eventHandler.bind(null, word); word._keyPressHandler = boundHandler; // 自定义属性存储 window.addEventListener("keypress", boundHandler); }); // 移除时直接取元素上存储的函数引用 const removeIT = () => { words.forEach(word => { if (word._keyPressHandler) { window.removeEventListener("keypress", word._keyPressHandler); // 移除后删除自定义属性,避免不必要的内存占用 delete word._keyPressHandler; } }); }
额外小技巧:用箭头函数替代bind(同样要存引用)
如果你不想用bind,也可以用箭头函数包裹实现参数传递,但同样要记得存储函数引用:
const boundKeyHandlers = []; words.forEach(word => { const handler = (e) => eventHandler(word, e); boundKeyHandlers.push(handler); window.addEventListener("keypress", handler); }); // 移除时使用同一个引用 const removeIT = () => { boundKeyHandlers.forEach(handler => { window.removeEventListener("keypress", handler); }); }
内容的提问来源于stack exchange,提问作者Sara Ree
相关产品推荐
相关产品推荐

