命名函数并向其添加事件侦听器会导致“未定义”

时间:2019-02-03 10:17:25

标签: javascript dom-events

我还是JavaScript的新手,但遇到了以下问题。

我想命名/声明我的函数,然后将其名称用作侦听器以轻松添加/删除点击事件。主要原因是这样,只要发生某种情况,我就可以删除点击事件。

我要实现的目标的简要说明:

function game() {
// 
}

我遇到的问题是当我添加这样的事件时:

for (let i = 0; i < cards.length; i++) {
    card = cards[i];
    card.addEventListener('click',  game);
}

命名函数游戏出现错误,提示:

  

我没有定义

但是,当我将函数作为匿名函数放在侦听器参数中时,不会发生此错误。

for (let i = 0; i < cards.length; i++) {
    card = cards[i];
    card.addEventListener('click', function game() {
      //
}

全局声明i不起作用,也没有传递i作为参数。

  • 具有匿名功能的完整代码:Here
  • 具有命名功能(我想要的工作)的完整代码:Here

3 个答案:

答案 0 :(得分:1)

要访问不同的i,您需要使用不同的闭包,因此您将获得不同的函数引用。您可以将它们直接存储在卡中,以便以后将其删除:

for (let i = 0; i < cards.length; i++) {
  const card = cards[i];
  card.addEventListener('click', card._click = function game() {
    //
  });
}

然后您可以通过以下方式将其删除:

card.removeEventListener("click", card._click);

如果您将game移到外面并为i添加一个咖喱参数(可能会更干净),也可以这样做:

const game = i => () => {
  // ...
 };

for (let i = 0; i < cards.length; i++) {
  const card = cards[i];
  card.addEventListener('click', card._click = game(i));
}

答案 1 :(得分:0)

您的问题是您的game函数不了解i,因为由于变量作用域的原因,i中的game不存在。为了解决这个问题,您可以像这样将i作为参数传递给game

card.addEventListener('click', _ => game(i));

在上一行中,您调用了箭头函数,然后调用了game函数。这使您可以将参数传递到game中。

然后在您的game方法中接受变量i作为参数:

function game(i) {

请参阅工作示例here

答案 2 :(得分:0)

您应该在JavaScript中阅读有关lexical scoping的信息,以了解为什么i在命名函数game中不可用

游戏内部函数只能引用词法范围内的变量(或本身在主题this中的变量)

简单地说,您可以将'i'传递给游戏以使其正常运行。但是由于addEventListener需要函数,因此您应该创建一个使用closure

的函数工厂。

修改游戏
let game = (i) => () => {
  //existing game function 
}

现在使用card.addEventListener('click', game(i));,它应该可以正常工作

这里有个有用的小提琴供您参考:https://jsfiddle.net/uch1arny/2/