【问题标题】:Javascript - element.addEventListener() returns "Uncaught TypeError"Javascript - element.addEventListener() 返回“未捕获的类型错误”
【发布时间】:2019-02-03 11:19:24
【问题描述】:

对于上下文,我正在尝试编写一个记忆游戏,您必须将两个相同颜色的圆圈配对,直到整个板子完成。我称它为Match-Two。以下是我将从中引用的代码:

class Circle {
    constructor(element, circleColor){
        this.elem = element;
        this.color = circleColor;
    }
}
var frequency = [0, 0, 0, 0, 0, 0, 0, 0];
var num; 
var hue = new Array(8);
var circle = new Array(16);

hue[0] = "#0039ff";
hue[1] = "#ff0000";
hue[2] = "#43ff00";
hue[3] = "#fffa00";
hue[4] = "#7405b5";
hue[5] = "#ff9d00";
hue[6] = "#ff00c3";
hue[7] = "#00fff6";

onload = function() {
    for(var i = 0; i < 16; i++){
        circle[i] = new Circle(document.getElementById("circle" + i));
        while(circle[i].color === undefined){
            num = Math.floor(Math.random() * 8);
            if(frequency[num] != 2){
                frequency[num]++;
                circle[i].color = hue[num];   
                circle[i].elem.addEventListener('click', function(){
                    main(circle[i])
                });
            }
        }
    }
}
function main(circle){
    circle.elem.style.backgroundColor = circle.color;
}

因此,在这段代码中,我创建了一个 Circle 类,并创建了一个 Circle 对象数组,该数组被标识为“circle”。加载页面时,我为每个圆圈对象提供一个来自我的 html 文档的元素引用(有 16 个圆圈,每个圆圈的 id 为 circle0、circle1、circle2.. 等。然后有一个小算法来确保只有两个矩阵中的每种颜色,所以它们都有一个匹配对。在 for 循环的每次迭代中,我为每个圆圈添加一个事件侦听器。如果单击圆圈,我希望它更改为存储在 color 中的颜色[i].color。但是,当我单击圆圈时,它返回的只是:

Uncaught TypeError: Cannot read property 'elem' of undefined
at main (script.js:39)
at HTMLDivElement.<anonymous> (script.js:31)

引用的是:

circle.elem.style.backgroundColor = circle.color;

所以我放了一些 console.log() 函数来看看发生了什么:

if(frequency[num] != 2){
    frequency[num]++;
    circle[i].color = hue[num];   
    console.log(circle[i].elem);
    console.log(circle[i].color);
    circle[i].elem.addEventListener('click', function(){
        main(circle[i])
    });
}

这正是我所期望的:

script.js:31 #ff9d00
script.js:30 div data-brackets-id=​"11" class=​"circle" id=​"circle1" /div
script.js:31 #ff9d00
script.js:30 div data-brackets-id=​"12" class=​"circle" id=​"circle2" /div
script.js:31 #0039ff
script.js:30 div data-brackets-id=​"13" class=​"circle" id=​"circle3" /div
script.js:31 #0039ff

所以它返回元素引用和圆的颜色。所以然后我尝试将“circle[i].elem.style.backgroundColor = circle[i].color”放入事件监听器中,我得到了和以前一样的问题......

if(frequency[num] != 2){
    frequency[num]++;
    circle[i].color = hue[num];   
    console.log(circle[i].elem);
    console.log(circle[i].color);
    circle[i].elem.addEventListener('click', function(){
        circle[i].elem.style.backgroundColor = circle[i].color
    });
}

Circles without their colors. The console log statements are on the right-hand side with their specific colors as well...

所以我放弃了,决定在事件侦听器之外编写那行确切的代码,看看是否可行,并将所有圆圈的颜色更改为它们的特定颜色...

if(frequency[num] != 2){
    frequency[num]++;
    circle[i].color = hue[num];   
    console.log(circle[i].elem);
    console.log(circle[i].color);
    circle[i].elem.style.backgroundColor = circle[i].color;
    circle[i].elem.addEventListener('click', function(){
        circle[i].elem.style.backgroundColor = circle[i].color
    });
}

The circles with their specific colors...

事件侦听器无法传递 Circle 或其他东西的对象存在一些问题...我不知道请帮助:(

【问题讨论】:

  • 您能否再次生成此错误消息,然后复制它指向的代码行(过去某个时间是第 39 行)并将其粘贴到您的问题中,以便我们查看哪个代码正在触发错误? Uncaught TypeError: Cannot read property 'elem' of undefined at main (script.js:39)
  • 尝试在你的 for 循环声明中使用 let i = 0 而不是 var i = 0

标签: javascript html css


【解决方案1】:

您的问题归结为 JS 处理 var 变量的方式 - 它们有点“泄漏”到全局范围内。

考虑您附加的事件侦听器:

circle[i].elem.addEventListener('click', function(){
  main(circle[i])
});

因此,每当触发侦听器时,它都会调用main() 函数并将circle[i] 传递给它。但由于i 是泄漏到假定范围之外的变量,它始终具有16 的值——在for 循环的最后一次迭代中分配给它的值。这就是main() 函数尝试访问undefinedstyle 属性的原因——传递给它的是circle[16] 的值。

这里有几种解决方法:

如果可以使用 ES6 let 变量:

for 循环中使用 let i 而不是 var i

for (let i = 0; i < 16; i++) {
  //...
}

如果没有,经典的函数闭包方式:

function createListener(j) {
  return function () {
    main(circle[j])
  }
}
// and use it in your 'for' loop later:
circle[i].elem.addEventListener('click', createListener(i));

这是一个有用的主题,它提供了更多避免这种情况的技术:JavaScript closure inside loops – simple practical example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-03
    • 2019-02-20
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2011-11-15
    相关资源
    最近更新 更多