说我有以下代码:
class Sample {
constructor() {
this.value = 'something';
}
addClickListener(e) { // e is a dom element
let func = function(e) {
//what I want to be able to do:
this.doThing(e);
}
e.addEventListener('click', func, false);
}
removeClickListener(e) {
let func = function(e) {
//what I want to be able to do:
this.doThing(e);
}
e.removeEventListener('click', func, false);
}
doThing(p) {
//code
}
}
我希望能够从'func'中引用一个类方法并将其传递一个参数。引用该类(例如让this = self)无效,因为每次调用该函数并更改事件侦听器的签名时,都会对此类进行新版本的引用。
答案 0 :(得分:2)
要删除事件监听器,您需要保留对要删除的函数的引用:
class Sample {
constructor() {
this.value = 'something';
// I've changed it from "let func" to "this.func" so we retain a reference
// I also moved it from addClickListener to the constructor so that we
// don't overwrite our reference when binding more elements to the
// same function
this.func = function(e) {
//what I want to be able to do:
this.doThing(e); // NOTE: You have another bug here. See comments
}
}
addClickListener(e) { // e is a dom element
// Replaced "func" with "this.func"
e.addEventListener('click', this.func, false);
}
removeClickListener(e) {
// Removed the new (unused) function
// Replaced "func" with "this.func"
e.removeEventListener('click', this.func, false);
}
doThing(p) {
//code
}
}
在我的评论中,我说:“注意:您在这里还有另一个错误”
调用事件侦听器时,上下文(this
变量)将更改为发出事件的元素。因此,this.doThing
将尝试在元素doThing
上调用e
!
还要注意,e
元素(传递给addClickListener
的参数与事件e
相同, 不是 (参数传递给this.func
)
要修复此错误,您需要存储对该类的引用,并在函数定义中使用该引用:
constructor() {
this.value = 'something';
let self = this;
this.func = function(e) {
self.doThing(e);
}
}
此处self
将像this
一样被 不会 覆盖,因此我们可以安全地使用它来引用类实例
当我重新阅读问题时,我意识到您的函数实际上只是在调用另一个函数。因此,为什么不将要最终运行的功能传递给addEventListener
?
class Sample {
constructor() {
this.value = 'something';
}
addClickListener(e) {
e.addEventListener('click', this.doThing, false);
}
removeClickListener(e) {
e.removeEventListener('click', this.doThing, false);
}
doThing(p) {
//code
}
}
请注意,这仍然会存在this
被调用事件的元素替换的问题,因此在doThing
中您不能说this.doOtherThing
来调用第二类方法。如果您希望这样做,则需要使用JavaScript的.bind()
方法创建一个 绑定方法 ,
class Sample {
constructor() {
this.value = 'something';
this.boundMethod = this.doThing.bind(this);
}
addClickListener(e) {
e.addEventListener('click', this.boundMethod, false);
}
removeClickListener(e) {
e.removeEventListener('click', this.boundMethod, false);
}
doThing(p) {
//code
this.doOtherThing(p);
//more code
}
doOtherThing(p) {
//code
}
}
正如@evolutionxbox指出的那样,您也可以使用箭头功能。此解决方案如下所示:
class Sample {
constructor() {
this.value = 'something';
this.boundMethod = p => { this.doThing(p); };
}
addClickListener(e) {
e.addEventListener('click', this.boundMethod, false);
}
removeClickListener(e) {
e.removeEventListener('click', this.boundMethod, false);
}
doThing(p) {
//code
this.doOtherThing(p);
//more code
}
doOtherThing(p) {
//code
}
}
之所以可行,是因为箭头函数是绑定方法的简写:
x => x + 1;
// Is functionally equivalent to:
(function(x) {
return x + 1;
}).bind(this);
许多人没有意识到箭头功能包括隐式bind
,并且在90%的用例中都没有关系(例如array.map(x => x + 1)
并不关心{{ 1}}),但是在类中,这种简写实际上是有价值的,因此在JavaScript类中使用箭头函数以避免覆盖this
变量已成为一种相当普遍的模式。