我有两个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
以及如何修复它。
答案 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
来引用相关元素。
但是第二个实现中的问题是调用函数而不是赋值。
如果您想向回调发送其他数据,可以使用功能call
或apply
:
element.addEventListener('click', function(){
var obj = { addtional: 'data' };
myCallback.call(this, obj);
})
function myCallback (obj){
console.log(this.id, obj);
}
call()方法调用一个函数,该函数具有给定的值和单独提供的参数。
apply()方法调用一个给定此值的函数,并将参数作为数组(或类数组对象)提供。