在绑定方法中获取 class 的 this 上下文,同时保留绑定 this
Get the this context of the class in a bound method while preserving bound this
我正在为 addEventListener 创建一个小助手 class。我 运行 遇到的问题是我无法有效地同时获得 class 的 this 上下文和事件(附加的事件目标)的 this 上下文。
(1) 如果我使用箭头函数,我可以获得 class 的 this,但我无法获得绑定的 this(通过 Function.prototype.call)
(2) 如果我使用函数表达式,我可以获得绑定的this,但我无法访问class。
(3) 我也不能使用内部闭包。 function/method 必须从外部范围引用。
这是一个简化的示例,可以向您展示我的意思。有没有办法勾选所有方框?我所能想到的就是创建另一个助手 class,它将为每个附加的事件侦听器进行初始化,但如果有更简单的方法,这似乎不是很有效。
class EventListenerHelper {
private targets: Array<EventTarget>
constructor() {
// If there was a single target, it would be very easy. But there are multiple
this.targets = [
document.body,
window
];
}
/**
* (1) - Try to use an arrow function
*
* This falls short because it's not possible to get the this context of the Event
*/
private attachWithArrowFunction() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackArrow, false);
});
}
private listenerCallbackArrow = (e: Event) => {
// Cannot get event this
const eventThis = undefined;
// Note that e.target is the innermost element which got hit with the event
// We are looking for that target that had the event listener attached
// If I'm not mistaken, the only way to get it is from the this context
// which is bound to the event callback
this.processListener(eventThis, e);
}
/**
* (2) - Try to use a regular class method
*
* This falls short because it's not possible to get the this context of the class
*/
private attachWithClassMethod() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackMethod, false);
});
}
private listenerCallbackMethod(e: Event) {
// Here we have the eventThis
const eventThis = this;
// But the class instance is completely unreachable
}
/**
* (3) - Try to create a closure wrapper
*
* This almost works, but it's not possible to removeEventListener later
*/
private attachWithClosure() {
let self = this;
this.targets.forEach((target) => {
target.addEventListener('click', function(e: Event) {
self.processListener(this as EventTarget, e);
}, false);
});
}
private processListener(eventThis: EventTarget, e: Event) {
// Do some stuff with other class methods
//
}
private detach() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackArrow, false);
});
}
}
一个常见的处理方法是return一个函数:
private attach() {
const listener = this.getListener()
this.targets.forEach(target => {
target.addEventListener('click', listener, false)
})
}
private getListener() {
const self = this
return function (e: Event) {
// self if EventListenerHelper this
// this is Event this
}
}
但我看不到它有什么好处,因为你传递给 addEventListener
的函数中的 this
等于 event.currentTarget
,所以你可以绑定你的监听器并使用 属性 而不是 this
:
constructor() {
// ...
this.listener = this.listener.bind(this)
}
private listener(e) {
// this is EventListenerHelper this
// e.currentTarget is Event this
}
我正在为 addEventListener 创建一个小助手 class。我 运行 遇到的问题是我无法有效地同时获得 class 的 this 上下文和事件(附加的事件目标)的 this 上下文。
(1) 如果我使用箭头函数,我可以获得 class 的 this,但我无法获得绑定的 this(通过 Function.prototype.call)
(2) 如果我使用函数表达式,我可以获得绑定的this,但我无法访问class。
(3) 我也不能使用内部闭包。 function/method 必须从外部范围引用。
这是一个简化的示例,可以向您展示我的意思。有没有办法勾选所有方框?我所能想到的就是创建另一个助手 class,它将为每个附加的事件侦听器进行初始化,但如果有更简单的方法,这似乎不是很有效。
class EventListenerHelper {
private targets: Array<EventTarget>
constructor() {
// If there was a single target, it would be very easy. But there are multiple
this.targets = [
document.body,
window
];
}
/**
* (1) - Try to use an arrow function
*
* This falls short because it's not possible to get the this context of the Event
*/
private attachWithArrowFunction() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackArrow, false);
});
}
private listenerCallbackArrow = (e: Event) => {
// Cannot get event this
const eventThis = undefined;
// Note that e.target is the innermost element which got hit with the event
// We are looking for that target that had the event listener attached
// If I'm not mistaken, the only way to get it is from the this context
// which is bound to the event callback
this.processListener(eventThis, e);
}
/**
* (2) - Try to use a regular class method
*
* This falls short because it's not possible to get the this context of the class
*/
private attachWithClassMethod() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackMethod, false);
});
}
private listenerCallbackMethod(e: Event) {
// Here we have the eventThis
const eventThis = this;
// But the class instance is completely unreachable
}
/**
* (3) - Try to create a closure wrapper
*
* This almost works, but it's not possible to removeEventListener later
*/
private attachWithClosure() {
let self = this;
this.targets.forEach((target) => {
target.addEventListener('click', function(e: Event) {
self.processListener(this as EventTarget, e);
}, false);
});
}
private processListener(eventThis: EventTarget, e: Event) {
// Do some stuff with other class methods
//
}
private detach() {
this.targets.forEach((target) => {
target.addEventListener('click', this.listenerCallbackArrow, false);
});
}
}
一个常见的处理方法是return一个函数:
private attach() {
const listener = this.getListener()
this.targets.forEach(target => {
target.addEventListener('click', listener, false)
})
}
private getListener() {
const self = this
return function (e: Event) {
// self if EventListenerHelper this
// this is Event this
}
}
但我看不到它有什么好处,因为你传递给 addEventListener
的函数中的 this
等于 event.currentTarget
,所以你可以绑定你的监听器并使用 属性 而不是 this
:
constructor() {
// ...
this.listener = this.listener.bind(this)
}
private listener(e) {
// this is EventListenerHelper this
// e.currentTarget is Event this
}