Javascript 在绑定方法中获取类的this上下文,同时保留绑定

Javascript 在绑定方法中获取类的this上下文,同时保留绑定,javascript,typescript,dom-events,Javascript,Typescript,Dom Events,我正在为addEventListener创建一个小助手类。我遇到的问题是,我无法有效地获取类的this上下文和事件的this上下文(附加的事件目标) (1) 如果我使用arrow函数,我可以得到类的this,但是我不能得到绑定的this(通过function.prototype.call) (2) 如果我使用一个函数表达式,我可以得到这个绑定,但是我不能访问这个类 (3) 我也不能使用内部闭包。函数/方法必须从外部范围引用 这是一个简单的例子来告诉你我的意思。有没有办法勾选所有方框?我所能想到的

我正在为addEventListener创建一个小助手类。我遇到的问题是,我无法有效地获取类的this上下文和事件的this上下文(附加的事件目标)

(1) 如果我使用arrow函数,我可以得到类的this,但是我不能得到绑定的this(通过function.prototype.call)

(2) 如果我使用一个函数表达式,我可以得到这个绑定,但是我不能访问这个类

(3) 我也不能使用内部闭包。函数/方法必须从外部范围引用

这是一个简单的例子来告诉你我的意思。有没有办法勾选所有方框?我所能想到的就是创建另一个helper类,该类将为附加的每个事件侦听器初始化,但如果有更简单的方法,这似乎不是很有效

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);
        });
    }

}
类EventListenerHelper{
私有目标:数组
构造函数(){
//如果只有一个目标,那就很容易了。但是有多个目标
这一点。目标=[
文件正文,
窗口
];
}
/**
*(1)-尝试使用箭头功能
* 
*这是不够的,因为无法获取事件的上下文
*/
私有AttachWithArrow函数(){
this.targets.forEach((target)=>{
target.addEventListener('click',this.listenerCallbackArrow,false);
});
}
私有listenerCallbackArrow=(e:Event)=>{
//无法获取此事件
const eventThis=未定义;
//注意,e.target是事件命中的最内层元素
//我们正在寻找连接了事件侦听器的目标
//如果我没有弄错的话,唯一的方法就是从这个上下文中得到它
//它绑定到事件回调
this.processListener(eventThis,e);
}
/**
*(2)-尝试使用常规类方法
* 
*这是不够的,因为不可能获得类的上下文
*/
私有attachWithClassMethod(){
this.targets.forEach((target)=>{
target.addEventListener('click',this.listenerCallbackMethod,false);
});
}
私有listenerCallbackMethod(e:事件){
//这是我们今天的活动
const eventThis=this;
//但是类实例是完全不可访问的
}
/**
*(3)-尝试创建闭包包装器
* 
*这几乎可以正常工作,但以后不可能删除VentListener
*/
私人attachWithClosure(){
让自我=这个;
this.targets.forEach((target)=>{
target.addEventListener('click',函数(e:事件){
processListener(作为EventTarget,e);
},假);
});
}
私有processListener(eventThis:EventTarget,e:Event){
//用其他类方法做一些事情
// 
}
私家侦探(){
this.targets.forEach((target)=>{
target.addEventListener('click',this.listenerCallbackArrow,false);
});
}
}

处理此问题的常用方法是返回函数:

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
}

处理此问题的常用方法是返回函数:

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
}

因此,如果您需要这两个上下文,为什么不指定一个变量-self=this。这是因为这样我就无法引用闭包之外的函数。请参阅代码中的(3)个案例。简单。让自己;班级。。。。构造函数(){self=this….它不是一个静态方法。类实例的上下文将丢失。因此,如果您同时需要这两个上下文,为什么不分配一个变量-self=this。这是因为这样我将无法引用闭包外的函数。请参见代码中的(3)案例。简单。让self;class….constructor(){self=this….这不是一个静态方法。类实例的上下文将丢失。嗯,关于currentTarget,你是对的。我之前忽略了它,因为我在控制台时它的值为null。记录它,但那是因为它只在事件期间设置。谢谢你提供了这两个解决方案,我显然会使用currentTarget,但这样做很好知道返回函数的诀窍嗯,你对currentTarget的看法是对的。我之前忽略了它,因为我在console.logged时它的值为null,但那是因为它只在事件期间设置。谢谢你提供了这两种解决方案,我显然会使用currentTarget,但是知道返回函数的诀窍很好