当参数传递给函数时,“this”停止工作

时间:2016-08-02 23:21:35

标签: javascript event-handling this

我有两个javascript函数,一个将eventhandler附加到整个元素类,另一个在激活事件处理程序时调用:

function attachDefinition(obj) {
    var classArr = document.getElementsByClassName("flashcards");
    for (let i = 0, len = classArr.length; i < len; i++) {
        classArr[i].addEventListener('click', cardClicked);
    }
}

function cardClicked(obj) {
    console.log(this.id);
    console.log(obj);
    var img = document.createElement('img');
    img.src = 'https://www.wordnik.com/img/wordnik_badge_a2.png';
    document.getElementById(this.id).innerHTML = '';
    document.getElementById(this.id).appendChild(img);
}

上述功能在点击时运行时没有错误。记录到控制台的this.id显示被单击的div元素的id,并且obj记录全局对象。

这很好但是我需要传入一个在程序中的不同函数中创建的对象。上面的代码只需要将obj参数添加到addEventListener调用,但是当我这样做时,一切都崩溃了。这段代码:

function attachDefinition(obj) {
    var classArr = document.getElementsByClassName("flashcards");
    for (let i = 0, len = classArr.length; i < len; i++) {
        classArr[i].addEventListener('click', cardClicked(obj)); //only thing I've changed!
    }
}

function cardClicked(obj) {
    console.log(this.id);
    console.log(obj);
    var img = document.createElement('img');
    img.src = 'https://www.wordnik.com/img/wordnik_badge_a2.png';
    document.getElementById(this.id).innerHTML = '';
    document.getElementById(this.id).appendChild(img);
}

现在成功控制台记录传入的对象,但现在未定义行记录this.id,并且我得到“无法在innerHTML行上设置未定义或空引用的属性'innerHTML'。

我很难理解为什么传递参数会改变this以及如何修复它。

3 个答案:

答案 0 :(得分:2)

如果我们假设你的

classArr[i].addEventListener('click', cardClicked(obj);

真的是

classArr[i].addEventListener('click', cardClicked(obj));
// Note ---------------------------------------------^

调用 cardClicked并将其返回值传递到addEventListener,完全按照foo(bar()) 调用 {的方式{1}}并将其返回值传递给bar

但是foo期望第二个参数中有一个函数,而addEventListener不会返回函数。

相反,由于您依赖于cardClicked引用this中的点击元素,您需要:

cardClicked

classArr[i].addEventListener('click', function() {
    cardClicked.call(this, obj);
});

第一种方法是通过调用classArr[i].addEventListener('click', cardClicked.bind(classArr[i], obj)); 来响应点击,使其看到的cardClicked与匿名函数收到的this相同。

第二种方法是使用this创建一个新函数,在调用时,将调用Function#bind并将cardClicked设置为this的漏洞及其第一个参数设为classArr[i]

答案 1 :(得分:1)

将您的classArr[i].addEventListener('click', cardClicked(obj);改为:

classArr[i].addEventListener('click', function() {
    cardClicked(obj);
});

首先,您错过了原版中的)。另外,在setInterval中传递参数时需要创建一个匿名函数,否则有问题的函数会在读取后立即执行。

答案 2 :(得分:1)

当您将一个函数作为触发器上的操作分配给事件时,函数的this将指向哪个事件触发的元素。您的第一个实现使用此优势,然后您可以在函数中使用this来引用相关元素。

但是第二个实现中的问题是调用函数而不是赋值。

如果您想向回调发送其他数据,可以使用功能callapply

element.addEventListener('click', function(){
    var obj = { addtional: 'data' };
    myCallback.call(this, obj);
})

function myCallback (obj){
    console.log(this.id, obj);
}

function.prototype.call

  

call()方法调用一个函数,该函数具有给定的值和单独提供的参数。

function.prototype.apply

  

apply()方法调用一个给定此值的函数,并将参数作为数组(或类数组对象)提供。