94

我知道这可能是痛苦的基本,但我很难把头绕过去。

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

而且,我不相信我做对了。我想要的最后一件事是我的大部分班级都有需要访问的 aa() 函数,aProxy()因为我觉得我正在写两次相同的东西?正常吗?

4

7 回答 7

133

如果你想this捕获 TypeScript 的方法是通过箭头函数。引用安德斯的话:

thisin 箭头函数是词法范围的

这是我喜欢使用它的方式:

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;      
}

在 TypeScript Playground 中查看

可以看到在生成的 JavaScript是在函数调用之外this捕获的:

var _this = this;
this.prop = 10;
this.func1 = function (arg) {
    return arg + " yeah" + _this.prop;
};

所以this函数调用中的值(可能是window)不会被使用。

要了解更多信息:“理解thisTypeScript”(4:05) – YouTube

于 2013-04-22T23:42:47.140 回答
20

如果你这样写你的方法,'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));
    }
}
于 2013-12-07T01:55:33.227 回答
7

请参阅 typescript 语言规范的第 72 页 https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true

箭头函数表达式

在示例中

class Messenger {
 message = "Hello World";
 start() {
 setTimeout(() => alert(this.message), 3000);
 }
};
var messenger = new Messenger();
messenger.start();

使用箭头函数表达式会导致回调与周围的“开始”方法具有相同的 this。将回调编写为标准函数表达式,必须手动安排对周围 this 的访问,例如通过将其复制到局部变量中:

这是实际生成的 Javascript:

class Messenger {
 message = "Hello World";
 start() {
 var _this = this;
 setTimeout(function() { alert(_this.message); }, 3000);
 }
};
于 2014-05-22T22:52:27.547 回答
7

聚会很晚,但我认为对于这个问题的未来访客来说,考虑以下几点非常重要:

其他答案,包括接受的答案,错过了一个关键点:

myFunction() { ... }

myFunction = () => { ... }

不是同一件事“除了后者捕获this

第一种语法在原型上创建一个方法,而第二种语法在其值为函数的对象上创建一个属性(也恰好捕获this)。您可以在转译的 JavaScript 中清楚地看到这一点。

要完整:

myFunction = function() { ... }

与第二种语法相同,但没有捕获。

因此,在大多数情况下使用箭头语法将解决您绑定到对象的问题,但它并不相同,并且在许多情况下您确实希望在原型上使用适当的函数而不是属性。

在这些情况下,使用代理或.bind()实际上正确的解决方案。(虽然可读性不好。)

在这里阅读更多内容(主要不是关于 TypeScript,而是原则立场):

https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1

https://ponyfoo.com/articles/binding-methods-to-class-instance-objects

于 2019-04-15T09:46:42.400 回答
5

当您将函数作为回调传递时,就会出现问题。到回调执行时,“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 的值。

于 2015-11-05T12:17:19.037 回答
3

简而言之,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
  }
};
于 2013-04-22T22:45:15.887 回答
2

这样做怎么样?声明一个“myClass”类型的全局变量并在类的构造函数中初始化它:

var _self: myClass;

class myClass {
    classScopeVar: string = "hello";

    constructor() {
        _self = this;
    }

    alerter() {
        setTimeout(function () {
            alert(_self.classScopeVar)
        }, 500);
    }
}

var classInstance = new myClass();
classInstance.alerter();

注意:重要的是不要使用“自我”,因为它已经具有特殊含义。

于 2019-10-19T20:54:45.370 回答