在jQuery回调中调用时,TypeScript“ this”作用域问题

我不确定在TypeScript中处理“ this”作用域的最佳方法。

这是我要转换为TypeScript的代码中常见模式的示例:

class DemonstrateScopingProblems {
    private status = "blah";
    public run() {
        alert(this.status);
    }
}

var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run(); 
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run); 

现在,我可以将呼叫更改为...

$(document).ready(thisTest.run.bind(thisTest));

...有效 但这有点可怕。这意味着在某些情况下,所有代码都可以编译并正常工作,但是如果我们忘记绑定范围,它将被破坏。

我想要一种在类中执行此操作的方法,这样在使用类时,我们无需担心“ this”的作用域。

有什么建议么?

更新资料

另一种可行的方法是使用粗箭头:

class DemonstrateScopingProblems {
    private status = "blah";

    public run = () => {
        alert(this.status);
    }
}

那是有效的方法吗?

和田2020/05/28 14:53:41

您在这里有几个选择,每个选择都有其自身的取舍。不幸的是,没有明显的最佳解决方案,它实际上取决于应用程序。

自动类绑定
如您的问题所示:

class DemonstrateScopingProblems {
    private status = "blah";

    public run = () => {
        alert(this.status);
    }
}
  • 好/不好:这将为您的类的每个实例的每个方法创建一个额外的闭包。如果通常只在常规方法调用中使用此方法,那就太过分了。但是,如果在回调位置上使用了大量的代码,则对于类实例而言,捕获this上下文而不是每个调用站点在调用时创建一个新的闭包更为有效
  • 良好:外部呼叫者无法忘记处理this上下文
  • 良好:TypeScript中的Typesafe
  • 很好:如果函数具有参数,则无需额外的工作
  • 坏:派生类无法调用以这种方式编写的基类方法 super.
  • 错误:哪些方法是“预绑定”的,哪些没有在您的类及其使用者之间创建额外的非类型安全协定的确切语义。

Function.bind
也如图所示:

$(document).ready(thisTest.run.bind(thisTest));
  • 好/不好:与第一种方法相比,内存/性能处于相反的平衡
  • 很好:如果函数具有参数,则无需额外的工作
  • 不好:在TypeScript中,当前没有类型安全性
  • 错误:仅对您有影响,仅在ECMAScript 5中可用
  • 不好:您必须两次输入实例名称

粗体箭头
在TypeScript中(出于解释原因,此处显示了一些虚拟参数):

$(document).ready((n, m) => thisTest.run(n, m));
  • 好/不好:与第一种方法相比,内存/性能处于相反的平衡
  • 良好:在TypeScript中,这具有100%的类型安全性
  • 良好:可在ECMAScript 3中使用
  • 好:您只需键入一次实例名称
  • 坏:您必须输入两次参数
  • 坏:不适用于可变参数
古一2020/05/28 14:53:41

在您的代码中,您是否尝试过仅按以下方式更改最后一行?

$(document).ready(() => thisTest.run());