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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14486930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 16:58:29  来源:igfitidea点击:

Typescript event handler function for event type field - Incorrect context

javascripttypescript

提问by parliament

This is a jquery interface from jquery.d.ts:

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

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

This is my custom interface mimicking partial functionality of the DialogOptions interface of jquery.d.ts:

这是我的自定义界面,模仿 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"); 

The last line fires OpenHandler()but inside it, thisis not type BaseDialog(unlike in NonEventHandlerMethod).

最后一行触发,OpenHandler()但在其中,this不是类型BaseDialog(与 in 不同NonEventHandlerMethod)。

The reason I need an event handler function for the dialog options field and the reason why I can't simply do this:

我需要对话框选项字段的事件处理程序函数的原因以及我不能简单地执行此操作的原因:

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

is because I need to add additional open-event handling logic in classes that extend DialogClass and there is no differentiation between this.member and super.member... there is only differentiation between this.function() and super.function():

是因为我需要在扩展 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
      } 
      ...
 } 

I think this may be a bug because

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

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

and calling the method directly:

并直接调用该方法:

   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.

回答by Fenton

TypeScript follows the usual JavaScript scoping conventions, so thiswill be dependent on context. If you have a method on a class that fires based on an event, thiswill be the event target. When you directly call a method on a class, thiswill be the class.

TypeScript 遵循通常的 JavaScript 范围约定,因此this将取决于上下文。如果您在基于事件触发的类上有一个方法,this则将是事件目标。当您直接在类上调用方法时,this将是该类。

If you want to get around this, you can take advantage of how JavaScript walks up the scope chain by giving thisan alias...

如果你想解决这个问题,你可以通过给this一个别名来利用 JavaScript 如何沿着作用域链向上走......

Here is one way to do that:

这是一种方法:

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

The arrow-function syntax creates and alias name _thisin the JavaScript.

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

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

We accept the cleverly aliased version of thisas a parameter and context.someFieldshould have the value we are after.

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