我有两个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
创建一个新函数,该函数在调用时将调用cardClicked
,this
设置为 classArr[i]
的 avlue,其第一个参数设置为 obj
。
将classArr[i].addEventListener('click', cardClicked(obj);
更改为以下内容:
classArr[i].addEventListener('click', function() {
cardClicked(obj);
});
首先,你在原版中缺少一个)
。此外,在 setInterval 中传递参数时需要创建一个匿名函数,否则相关函数将在读取后立即执行。
函数分配给事件作为触发器上的操作时,该函数的this
将指向触发事件的元素。 您的第一个实现利用了这一优势,然后您可以在函数中使用this
来引用相关元素。
但是第二个实现中的问题是调用函数而不是赋值。
如果要向回调发送其他数据,可以使用函数call
或apply
:
element.addEventListener('click', function(){
var obj = { addtional: 'data' };
myCallback.call(this, obj);
})
function myCallback (obj){
console.log(this.id, obj);
}
函数.原型.调用
call(( 方法调用具有给定此值和单独提供的参数的函数。
函数.原型.应用
apply(( 方法调用具有给定此值和作为数组(或类似数组的对象(提供的参数的函数。