嵌套函数无法在Typescript中找到它自己

时间:2018-06-15 19:05:28

标签: html5 typescript canvas html5-canvas

我有以下代码:

//Main Entry Point.
start() {
    this.init();
    this.gameLoop();
}

//Init, runs only once.
init() {
    let initalEntity1: Entity = new Entity(10, 10, Gender.female);
    let initalEntity2: Entity = new Entity(60, 60, Gender.male);
    console.log("There are " + this.Entities.length + " Items in the entities Array")
    this.Entities.push(initalEntity1, initalEntity2);
    console.log("There are " + this.Entities.length + " Items in the entities Array")
}

gameLoop() {
    console.log("Performing a Game Loop");
    requestAnimationFrame(this.gameLoop);

    //MAIN LOOP THROUGH ENTITIES
    for (let i in this.Entities) {
            this.Render.drawEntitysToScreen(this.Entities[i].EntityPosition, this.Entities[i].gender);
        }
}

它进入start()罚款,并执行所有init()功能。它们继续运行到gameloop(),它将运行一次,但是重新触发要被调用为Canvas框架的函数的行requestAnimationFrame(this.gameLoop);导致以下错误:

TypeError: this is undefined

尝试requestAnimationFrame(gameLoop);但它会导致打字稿编译器感到不安......

2 个答案:

答案 0 :(得分:1)

当您在this.gameLoop()内拨打start时,this内部的gameLoop的值将是gameLoop所属的类,因为您致电gameLoop作为this(该类)的属性。

传递函数引用时,this的值可能是从其他地方调用函数时的任何值。

解决方案1 ​​|使用Function.prototype.bind

当您将函数提供给bind时,{p> this requestAnimationFrame的值。通过这样做你明确地说:

bind的参数在this的任何调用中都是gameLoop,无论调用方式如何,或者调用它的位置。 < / p>

requestAnimationFrame(this.gameLoop.bind(this));

请注意,bind会返回新函数,因此仍然是类属性的原始gameLoop函数保持不变。

解决方案2 |使用arrow function

定义箭头函数以最终执行对gameLoop而非requestAnimationFrame的调用。箭头函数中的this值是静态的,并且是从包含函数声明的执行上下文继承的。

requestAnimationFrame(() => this.gameLoop());

答案 1 :(得分:1)

这是由于this绑定在javascript中的工作原理。您将this.gameLoop传递给requestAnimationFrame的方式实际上是传递未绑定的gameLoop函数,因此在调用它时,它已失去对其this的引用。< / p>

这个问题有很多可能的解决方案:

  1. 您可以将this.gameLoop绑定到类构造函数内部的this,如下所示:

    constructor() {
      this.gameLoop = this.gameLoop.bind(this);
    }
    
  2. 您可以将this.gameLoop绑定到this,作为gameLoop方法定义的一部分。而不是像gameLoop那样定义

    gameLoop() {
    

    如果您改为使用

    gameLoop = () => {
    

    它将自动绑定到this。这是使用胖箭头进行函数声明的属性:它自动执行与函数声明中存在的this的绑定。

  3. 您可以更改gameLooprequestAnimationFrame的方式:

    requestAnimationFrame(() => this.gameLoop());
    

    这再次利用了箭头函数执行的自动this绑定,但不是将其作为类方法声明的一部分,而是在您需要绑定时可以简单地执行它。

    但请注意,这样做意味着每次调用gameLoop时都会创建一个新函数。