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



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

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以及如何解决它。

如果我们假设您的

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

真的是

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

这是调用cardClicked并将其返回值传递给addEventListener,这正是foo(bar())调用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 创建一个新函数,该函数在调用时将调用cardClickedthis设置为 classArr[i] 的 avlue,其第一个参数设置为 obj

classArr[i].addEventListener('click', cardClicked(obj);更改为以下内容:

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

首先,你在原版中缺少一个)。此外,在 setInterval 中传递参数时需要创建一个匿名函数,否则相关函数将在读取后立即执行。

当您将

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

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

如果要向回调发送其他数据,可以使用函数callapply

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

函数.原型.调用

call(( 方法调用具有给定此值和单独提供的参数的函数。

函数.原型.应用

apply(( 方法调用具有给定此值和作为数组(或类似数组的对象(提供的参数的函数。

最新更新