我不知道最好的方法来处理“这个”在打字稿的作用域。
下面是我在转换到打字稿代码的通用模式的一个例子:
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));
......这确实工作。 但它有点可怕。 这意味着代码可以编译所有在某些情况下正常工作,但如果我们忘记范围绑定会破。
我想办法在类内做到这一点,所以在使用该类时,我们并不需要担心什么“本”的作用范围。
有什么建议?
更新
正在使用的脂肪箭头作品的另一种方法:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
那是一种有效的方法?
你有几个选择这里,每一个都有自己的权衡。 不幸的是没有明显的最佳解决方案,这将真正取决于应用。
自动绑定类
至于你的问题所示:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
- 好/坏:这将创建每类的实例方法,每一个附加的封闭。 如果此方法通常只在普通的方法调用中使用,这是矫枉过正。 但是,如果它使用了很多的回调位置,它的效率更高的类实例来捕捉
this
背景下,而不是每个调用点创建时调用一个新的闭包。 - 好:不可能的外部呼叫者忘记处理
this
背景下 - 好:类型安全的打字稿
- 好:没有额外的工作,如果函数参数
- 错误:派生类无法拨叫用这种方式基类的方法
super.
- 坏:方法是“预绑定”和它的精确语义不创建类和消费者之间的额外的非类型安全的合同。
Function.bind
此外,如下所示:
$(document).ready(thisTest.run.bind(thisTest));
- 好/坏:对面内存/性能权衡比较,第一种方法
- 好:没有额外的工作,如果函数参数
- △:打字稿,这个目前还没有类型安全
- 坏:只有在ECMAScript中5可用的,如果这对你很重要
- 缺点:你必须键入实例名称两次
脂肪箭头
在打字稿(这里示出具有用于说明原因,某些伪参数):
$(document).ready((n, m) => thisTest.run(n, m));
- 好/坏:对面内存/性能权衡比较,第一种方法
- 好:在打字稿,这个有100%的类型安全
- 好:工作中的ECMAScript 3
- 好:你只需要输入一次实例名称
- 缺点:你必须输入参数两次
- 缺点:不带可变参数的参数工作
需要一些初始设置,但与它的光无敌,字面一个字的语法回报另一种解决方案是使用方法装修通过吸气到JIT绑定的方法。
我创建了一个GitHub上的回购 ,以展示这个想法的实现(这是一个有点冗长,以适应一个答案,其代码40行,包括注释),你会简单地用如下:
class DemonstrateScopingProblems {
private status = "blah";
@bound public run() {
alert(this.status);
}
}
我还没有看到这在任何地方提到的是,但它完美的作品。 此外,也没有明显的缺点,以这种方法:这个装饰的实现- 包括一些类型检查的运行时类型安全 -是平凡和简单,并配备了最初的方法调用之后基本上是零开销。
主要部分被限定在类的原型,它是第一个呼叫之前立即执行以下吸气剂:
get: function () {
// Create bound override on object instance. This will hide the original method on the prototype, and instead yield a bound version from the
// instance itself. The original method will no longer be accessible. Inside a getter, 'this' will refer to the instance.
var instance = this;
Object.defineProperty(instance, propKey.toString(), {
value: function () {
// This is effectively a lightweight bind() that skips many (here unnecessary) checks found in native implementations.
return originalMethod.apply(instance, arguments);
}
});
// The first invocation (per instance) will return the bound method from here. Subsequent calls will never reach this point, due to the way
// JavaScript runtimes look up properties on objects; the bound method, defined on the instance, will effectively hide it.
return instance[propKey];
}
完整的源
这个想法也可采取一步,通过在一类装饰这样做代替,迭代的方法和限定一个通为他们每个人的上述属性描述符。
Necromancing。
有不通过吸气要求箭头函数(箭头函数是慢30%),或JIT的方法一个明显简单的解决方案。
该解决方案是绑定在构造函数中的这上下文。
class DemonstrateScopingProblems
{
constructor()
{
this.run = this.run.bind(this);
}
private status = "blah";
public run() {
alert(this.status);
}
}
您可以使用此方法来自动绑定所有功能在构造方法的类:
class DemonstrateScopingProblems
{
constructor()
{
this.autoBind(this);
}
[...]
}
export function autoBind(self: any)
{
for (const key of Object.getOwnPropertyNames(self.constructor.prototype))
{
const val = self[key];
if (key !== 'constructor' && typeof val === 'function')
{
// console.log(key);
self[key] = val.bind(self);
} // End if (key !== 'constructor' && typeof val === 'function')
} // Next key
return self;
} // End Function autoBind
在你的代码,你有没有尝试过将最后一行如下?
$(document).ready(() => thisTest.run());