问题 事件类型字段的Typescript事件处理函数 - 不正确的上下文


这是jquery.d.ts的jquery接口:

export interface IDialogEvent extends DialogEvent {
    (event: Event, ui: DialogUIParams): void;
}

这是我的自定义界面,模仿jquery.d.ts的DialogOptions接口的部分功能:

export interface IDialogOptions {
    open: IDialogEvent;
}

export class DialogClass implements IDialogOptions { 

    //Dialog options
    public open: IDialogEvent;

    //Class related fields
    public someField: any;
    public dialogEl: JQuery;

    constructor() { 
        this.open = this.OpenHandler;
        this.dialogEl = $("<div></div>").dialog(this); 
        //Passing "this" initializes the dialog by mapping relevant class fields
        //to the dialog's "option" object, in this case the only "relevant" field is "open".
    }

    public OpenHandler(event: Event, ui: DialogUIParams) { 
        var value = this.someField; //BAD. "this" is not type BaseClass
    }

    public NonEventHandlerMethod() { 
        var value = this.someField; //GOOD. "this" is type BaseClass
    }  
}

var dialog = new DialogClass();
dialog.dialogEl.dialog("open"); 

最后一行开火了 OpenHandler() 但在里面, this 不是类型 BaseDialog (与...不同 NonEventHandlerMethod)。

我需要一个对话框选项字段的事件处理函数的原因以及我不能简单地这样做的原因:

 export class DialogClass implements IDialogOptions { 
     ...
      constructor() { 
          this.open = () => {
                //event handling logic
          };
          ...
      }
      ...
 }        

是因为我需要在扩展DialogClass的类中添加额外的开放事件处理逻辑,并且this.member和super.member之间没有区别...... this.function()和super.function()之间只有区别:

 export class LoginDialog extends DialogClass { 
     ...
      constructor() { 
          this.open = this.OpenHandler;
          ...
      }

      public OpenHandler(event: Event, ui: DialogUIParams) { 
           super.OpenHandler(); //Base handling logic

           //Additional handling logic
      } 
      ...
 } 

我认为这可能是一个错误,因为

   export class DialogClass implements IDialogOptions { 
     ...
      constructor() { 
          this.open = () => {
                var test = this.someField;  //Correct context
          };
          ...
      }
      ...
   }  

并直接调用该方法:

   var dialog = new DialogClass();
   dialog.OpenHandler();  //Correct context when called directly
   //Note: I haven't actually tested this persay but this function is no different
   //than any other functionso a direct call should certainly not be problem.

11731
2018-01-23 18:38


起源



答案:


TypeScript遵循通常的JavaScript范围约定,因此 this 将取决于背景。如果您在基于事件触发的类上有方法, this 将成为活动目标。直接在类上调用方法时 this 将是班级。

如果你想解决这个问题,你可以利用JavaScript如何通过提供来扩展范围链 this 别名......

这是一种方法:

this.open = () => { this.OpenHandler(this); };

箭头函数语法创建和别名 _this 在JavaScript中。

public OpenHandler(context: DialogClass, event: Event, ui: DialogUIParams) { 
    var value = context.someField;
}

我们接受巧妙的别名版本 this 作为参数和 context.someField 应该具有我们追求的价值。


14
2018-01-23 20:31



再次感谢,史蒂夫!如果没有你一遍又一遍的大力帮助,我会落后。开始了解这一点。使用Typescript,我的代码看起来非常干净和可维护,我很喜欢它!顺便说一下,它只能使用显式签名:this.open =(event:Event,ui:DialogUIParams)=> {this.OpenHandler(this,event,ui); }; - parliament


答案:


TypeScript遵循通常的JavaScript范围约定,因此 this 将取决于背景。如果您在基于事件触发的类上有方法, this 将成为活动目标。直接在类上调用方法时 this 将是班级。

如果你想解决这个问题,你可以利用JavaScript如何通过提供来扩展范围链 this 别名......

这是一种方法:

this.open = () => { this.OpenHandler(this); };

箭头函数语法创建和别名 _this 在JavaScript中。

public OpenHandler(context: DialogClass, event: Event, ui: DialogUIParams) { 
    var value = context.someField;
}

我们接受巧妙的别名版本 this 作为参数和 context.someField 应该具有我们追求的价值。


14
2018-01-23 20:31



再次感谢,史蒂夫!如果没有你一遍又一遍的大力帮助,我会落后。开始了解这一点。使用Typescript,我的代码看起来非常干净和可维护,我很喜欢它!顺便说一下,它只能使用显式签名:this.open =(event:Event,ui:DialogUIParams)=> {this.OpenHandler(this,event,ui); }; - parliament