在类方法中打字“this”

时间:2013-04-22 22:30:12

标签: jquery this typescript proxy-classes

我知道这可能是非常痛苦的基础,但我很难把头缠在它周围。

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
     }

}

但是从Actioncript 3的背景来看,我并不确定这里发生了什么。抱歉,我不确定Javascript的开始位置和TypeScript结束。

updateProxy: () => void

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

7 个答案:

答案 0 :(得分:95)

如果你想要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)。

要了解详情:“Understanding this in TypeScript” (4:05) – YouTube

答案 1 :(得分:16)

如果你写这样的方法,'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));
    }
}

答案 2 :(得分:4)

请参阅打字稿语言规范的第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();
  

使用箭头函数表达式会导致回调   与周围的'start'方法相同。编写回调   作为标准函数表达式,有必要手动   安排进入周围,例如将其复制到   一个局部变量:

这是实际生成的Javascript:

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

答案 3 :(得分:4)

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

因为在特定的对象引用(_this)上调用了addFile函数,所以它不使用调用者的“this”而是使用_this的值。

答案 4 :(得分:2)

简而言之,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
  }
};

答案 5 :(得分:1)

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

其他答案,包括已接受的答案,都缺少关键点:

ResponseCacheAttribute

myFunction() { ... }

不是同一件事“除了后者捕获myFunction = () => { ... } ”。

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

要完整:

this

与第二种语法相同,但不包含捕获内容。

因此,在大多数情况下使用箭头语法 可以解决与对象绑定的问题,但这并不相同,在许多情况下,您确实希望在对象上具有适当的功能。原型而不是属性。

在这些情况下,使用代理或myFunction = function() { ... } 实际上 是正确的解决方案。 (尽管易读。)

此处有更多阅读内容(主要不是有关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

答案 6 :(得分:0)

这种方式怎么样? 声明类型为“ 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();

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