我知道这可能是基本的痛苦,但我很难绕过它。
class Main
{
constructor()
{
requestAnimationFrame(this.update); //fine
}
update(): void
{
requestAnimationFrame(this.update); //error, because this is window
}
}
似乎我需要一个代理,所以让我们说使用Jquery
class Main
{
constructor()
{
this.updateProxy = $.proxy(this.update, this);
requestAnimationFrame(this.updateProxy); //fine
}
updateProxy: () => void
update(): void
{
requestAnimationFrame(this.updateProxy); //fine
}
}
但是来自Actionscript 3的背景,我不确定这里发生了什么。抱歉,我不确定Javascript的开始位置和TypeScript结束。
updateProxy: () => void
而且,我不相信我这样做是对的。我想要的最后一件事就是我班上的大多数人都有一个a()函数需要用aProxy()
访问,因为我觉得我写两次同样的东西?这是正常的吗?
如果你想要this
捕获TypeScript的方式,这是通过箭头功能。引用安德斯:
箭头函数中的
this
是词法范围的
以下是我喜欢使用此方法的方法:
class test{
// Use arrow functions
func1=(arg:string)=>{
return arg+" yeah" + this.prop;
}
func2=(arg:number)=>{
return arg+10 + this.prop;
}
// some property on this
prop = 10;
}
View this in the TypeScript Playground
您可以看到在生成的JavaScript中,this
是在函数调用之外捕获的:
var _this = this;
this.prop = 10;
this.func1 = function (arg) {
return arg + " yeah" + _this.prop;
};
所以函数调用中的this
值(可能是window
)将不会被使用。
如果你写这样的方法,'this'将按你期望的方式对待。
class Main
{
constructor()
{
requestAnimationFrame(() => this.update());
}
update(): void
{
requestAnimationFrame(() => this.update());
}
}
另一种选择是将'this'绑定到函数调用:
class Main
{
constructor()
{
requestAnimationFrame(this.update.bind(this));
}
update(): void
{
requestAnimationFrame(this.update.bind(this));
}
}
将函数作为回调传递时会出现问题。在回调执行时,“this”的值可能已更改为Window,控件调用回调或其他内容。
确保在传递对要回调的函数的引用时始终使用lambda表达式。例如
public addFile(file) {
this.files.push(file);
}
//Not like this
someObject.doSomething(addFile);
//but instead, like this
someObject.doSomething( (file) => addFile(file) );
这编译成类似的东西
this.addFile(file) {
this.files.push(file);
}
var _this = this;
someObject.doSomething(_this.addFile);
因为addFile函数是在特定的对象引用(_this)上调用的,所以它不使用调用者的“this”而是使用_this的值。
请参阅打字稿语言规范https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true的第72页
在示例中
class Messenger {
message = "Hello World";
start() {
setTimeout(() => alert(this.message), 3000);
}
};
var messenger = new Messenger();
messenger.start();
使用箭头函数表达式会使回调与周围的'start'方法具有相同的效果。将回调写为标准函数表达式,有必要手动安排对周围环境的访问,例如将其复制到局部变量中:
这是实际生成的Javascript:
class Messenger {
message = "Hello World";
start() {
var _this = this;
setTimeout(function() { alert(_this.message); }, 3000);
}
};
简而言之,this关键字始终具有对调用该函数的对象的引用。
在Javascript中,因为函数只是变量,所以你可以传递它们。
例:
var x = {
localvar: 5,
test: function(){
alert(this.localvar);
}
};
x.test() // outputs 5
var y;
y.somemethod = x.test; // assign the function test from x to the 'property' somemethod on y
y.test(); // outputs undefined, this now points to y and y has no localvar
y.localvar = "super dooper string";
y.test(); // outputs super dooper string
当您使用jQuery执行以下操作时:
$.proxy(this.update, this);
你正在做的是覆盖这种背景。幕后花絮jQuery会给你这个:
$.proxy = function(fnc, scope){
return function(){
return fnc.apply(scope); // apply is a method on a function that calls that function with a given this value
}
};
聚会很晚,但我认为对于这个问题的未来访问者来说,考虑以下内容非常重要:
其他答案,包括被接受的答案,都错过了一个关键点:
myFunction() { ... }
和
myFunction = () => { ... }
不是同一件事“除了后者捕获this
”。
第一种语法在原型上创建一个方法,而第二种语法在对象上创建一个属性,其值是一个函数(也恰好捕获this
)。您可以在已编译的JavaScript中清楚地看到这一点。
完成:
myFunction = function() { ... }
将是第二种语法,但没有捕获。
因此,在大多数情况下使用箭头语法将解决绑定到对象的问题,但它并不相同,并且在许多情况下您确实希望在原型上具有适当的功能而不是属性。
在这些情况下,使用代理或.bind()
实际上是正确的解决方案。 (虽然可读性差。)
更多阅读在这里(主要不是关于TypeScript,但原则立场):
https://ponyfoo.com/articles/binding-methods-to-class-instance-objects