掌握带参数的JavaScript事件监听器处理技巧

本文深入探讨JavaScript中带参数的事件监听器处理方法,包括箭头函数、匿名函数和闭包的使用技巧,以及如何正确移除监听器避免内存泄漏,提升Web应用性能。

处理带参数的JavaScript事件监听器

JavaScript事件监听器对于实现交互性至关重要,但如果未正确移除,可能会悄悄导致内存泄漏。当事件监听器需要参数时,情况就变得更有趣了。Amejimaobari Ollornwi分享了哪些JavaScript特性使得处理带参数的事件处理器既可行又得到良好支持。

JavaScript事件监听器非常重要,因为它们存在于几乎所有需要交互性的Web应用程序中。尽管它们很常见,但正确管理它们也至关重要。管理不当的事件监听器可能导致内存泄漏,在极端情况下有时还会导致性能问题。

真正的问题是:JavaScript事件监听器在添加后通常不会被移除。而且当它们被添加时,大多数时候不需要参数——除了少数情况,这使得处理它们变得有些棘手。

一个常见的使用带参数事件处理器的场景是当您有一个动态任务列表时,列表中的每个任务都有一个“删除”按钮,该按钮附加到一个事件处理器,该处理器使用任务的ID作为参数来删除任务。在这种情况下,最好在任务完成后移除事件监听器,以确保已删除的元素可以成功清理,这个过程称为垃圾回收。

添加事件监听器时的常见错误

向事件处理器添加参数时的一个非常常见的错误是在addEventListener()方法中调用带参数的函数。我的意思是:

1
button.addEventListener('click', myFunction(param1, param2));

浏览器会立即调用该函数来响应这行代码,无论点击事件是否发生。换句话说,函数会立即被调用而不是被延迟,因此当点击事件实际发生时它永远不会触发。

在某些情况下,您可能还会收到以下控制台错误:

1
Uncaught TypeError: Failed to execute. addEventListener on EventTarget: parameter is not of type Object.

这个错误是有道理的,因为addEventListener方法的第二个参数只能接受JavaScript函数、具有handleEvent()方法的对象或简单的null。避免此错误的一个快速简单的方法是将addEventListener方法的第二个参数更改为箭头函数或匿名函数。

1
2
3
button.addEventListener('click', (event) => {
  myFunction(event, param1, param2); // 点击时运行
});

使用箭头函数和匿名函数的唯一问题是它们无法用传统的removeEventListener()方法移除;您将不得不使用AbortController,这对于简单的情况可能有些过度。当您需要一次移除多个事件监听器时,AbortController会大放异彩。

对于只需要移除一两个事件监听器的简单情况,removeEventListener()方法仍然很有用。但是,为了使用它,您需要将函数存储为监听器的引用。

使用带参数的事件处理器

有几种方法可以包含带参数的事件处理器。然而,出于演示目的,我们将把重点限制在以下两种:

选项1:箭头函数和匿名函数

使用箭头函数和匿名函数是完成任务的最快和最简单的方法。

要使用箭头函数和匿名函数添加带参数的事件处理器,我们首先需要在附加到事件监听器的箭头函数中调用我们要创建的函数:

1
2
3
4
5
const button = document.querySelector("#myButton");

button.addEventListener("click", (event) => {
  handleClick(event, "hello", "world");
});

之后,我们可以创建带参数的函数:

1
2
3
function handleClick(event, param1, param2) {
  console.log(param1, param2, event.type, event.target);
}

请注意,使用此方法,移除事件监听器需要AbortController。要移除事件监听器,我们创建一个新的AbortController对象,然后从中检索AbortSignal对象:

1
2
const controller = new AbortController();
const { signal } = controller;

接下来,我们可以将控制器的信号作为选项传递给removeEventListener()方法:

1
2
3
button.addEventListener("click", (event) => {
  handleClick(event, "hello", "world");
}, { signal });

现在我们可以通过调用AbortController.abort()来移除事件监听器:

1
controller.abort()

选项2:闭包

JavaScript中的闭包是另一个可以帮助我们处理事件处理器的特性。还记得产生类型错误的那个错误吗?那个错误也可以用闭包来纠正。具体来说,通过闭包,函数可以访问其外部作用域中的变量。

换句话说,我们可以从外部函数访问事件处理器中需要的参数:

1
2
3
4
5
6
7
8
9
function createHandler(message, number) {
  // 事件处理器
  return function (event) {
    console.log(`${message} ${number} - 点击的元素:`, event.target);
  };
}

const button = document.querySelector("#myButton");
button.addEventListener("click", createHandler("Hello, world!", 1));

这建立了一个返回另一个函数的函数。然后,创建的函数作为addEventListener()方法中的第二个参数被调用,以便内部函数作为事件处理器返回。借助闭包的力量,外部函数的参数将可供内部函数使用。

请注意事件对象是如何对内部函数可用的。这是因为内部函数是作为事件处理器附加的。事件对象自动传递给函数,因为它是事件处理器。

要移除事件监听器,我们可以像之前一样使用AbortController。但是,这次让我们看看如何使用removeEventListener()方法来实现。

为了使removeEventListener方法工作,需要存储对createHandler函数的引用并在addEventListener方法中使用:

1
2
3
4
5
6
7
function createHandler(message, number) {
  return function (event) {
    console.log(`${message} ${number} - 点击的元素:`, event.target);
  };
}
const handler = createHandler("Hello, world!", 1);
button.addEventListener("click", handler);

现在,可以这样移除事件监听器:

1
button.removeEventListener("click", handler);

结论

良好的实践是总是在不再需要时移除事件监听器,以防止内存泄漏。大多数时候,事件处理器不需要参数;然而,在少数情况下,它们需要。使用JavaScript特性如闭包、AbortControllerremoveEventListener,处理带参数的事件处理器既可行又得到良好支持。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计