我不确定在 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));
...这确实有效。但这有点可怕。这意味着代码在某些情况下都可以编译并正常工作,但如果我们忘记绑定(bind)作用域,它就会中断。
我想要一种在类中执行此操作的方法,以便在使用该类时我们无需担心“this”的作用域。
有什么建议吗?
更新
另一种有效的方法是使用粗箭头:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
这是一种有效的方法吗?
最佳答案
这里有几个选项,每个选项都有自己的权衡。不幸的是,没有明显的最佳解决方案,这实际上取决于应用程序。
自动类绑定(bind)
如您的问题所示:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
- 好/坏:这会为您的类的每个实例的每个方法创建一个额外的闭包。如果这个方法通常只用在常规方法调用中,那就太过分了。但是,如果它在回调位置使用很多,类实例捕获
this
上下文而不是每个调用站点在调用时创建一个新的闭包会更有效。 - 好:外部调用者不可能忘记处理
this
上下文 - 好:TypeScript 中的类型安全
- 好:如果函数有参数,则无需额外工作
- 缺点:派生类无法调用使用
super.
以这种方式编写的基类方法。 - 不好:哪些方法是“预绑定(bind)”的,哪些方法没有在您的类与其使用者之间创建额外的非类型安全契约的确切语义。
函数.bind
也如图:
$(document).ready(thisTest.run.bind(thisTest));
- 好/坏:与第一种方法相比,相反的内存/性能权衡
- 好:如果函数有参数,则无需额外工作
- 差:在 TypeScript 中,目前没有类型安全
- 差:仅在 ECMAScript 5 中可用,如果这对您很重要的话
- 不好:您必须输入实例名称两次
粗箭头
在 TypeScript 中(出于解释原因,此处显示了一些虚拟参数):
$(document).ready((n, m) => thisTest.run(n, m));
- 好/坏:与第一种方法相比,相反的内存/性能权衡
- 好:在 TypeScript 中,这具有 100% 的类型安全
- 良好:适用于 ECMAScript 3
- 很好:您只需输入一次实例名称
- 不好:您必须输入两次参数
- 差:不适用于可变参数
关于在 jquery 回调中调用时出现 TypeScript "this"范围问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20627138/