You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现游戏循环的类方法递归?解决requestAnimationFrame调用类方法时this指向异常问题

解决TypeScript中requestAnimationFrame调用类方法时this指向undefined的问题

你遇到的这个问题在类方法结合requestAnimationFrame使用时特别常见——当requestAnimationFrame回调执行gameLoop时,函数的上下文(也就是this)并没有绑定到你的Main类实例,导致this变成了undefined,自然找不到this.draw方法。

下面给你几种实用的解决方案:

方法1:使用箭头函数定义gameLoop

箭头函数不会创建自己的this,它会捕获定义时所在上下文的this(也就是你的Main实例)。直接把gameLoop改成箭头函数即可:

export default class Main {
  canvas: HTMLCanvasElement | null;
  context: CanvasRenderingContext2D | null;

  constructor() {
    this.canvas = null;
    this.context = null;
  }

  init() {
    this.canvas = <HTMLCanvasElement>document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');
    window.requestAnimationFrame(this.gameLoop);
    return () => { };
  }

  draw() {
    const randomColor = Math.random() > 0.5 ? '#ff8080' : '#0099b0';
    this.context.fillStyle = randomColor;
    this.context.fillRect(100, 50, 200, 175);
  }

  // 改成箭头函数,自动绑定类实例的this
  gameLoop = (timestamp: number) => {
    this.draw();
    window.requestAnimationFrame(this.gameLoop);
  }

  core() {
    window.onload = this.init();
  }
}

const main = new Main();
main.core();

方法2:在requestAnimationFrame中用箭头函数包裹调用

如果不想修改gameLoop的定义,可以在传递给requestAnimationFrame的时候,用箭头函数包裹this.gameLoop调用,这样箭头函数会保留实例的this:

// 修改init和gameLoop部分
init() {
  this.canvas = <HTMLCanvasElement>document.getElementById('canvas');
  this.context = this.canvas.getContext('2d');
  // 用箭头函数包裹,确保this指向实例
  window.requestAnimationFrame((timestamp) => this.gameLoop(timestamp));
  return () => { };
}

gameLoop(timestamp: number) {
  this.draw();
  // 同样在这里用箭头函数包裹递归调用
  window.requestAnimationFrame((timestamp) => this.gameLoop(timestamp));
}

方法3:在构造函数中绑定this到gameLoop

在类的构造函数里,用bind方法把gameLoop的this永久绑定到当前实例,这样无论gameLoop被谁调用,this都指向实例:

constructor() {
  this.canvas = null;
  this.context = null;
  // 绑定this到gameLoop
  this.gameLoop = this.gameLoop.bind(this);
}

// 后面的gameLoop和原来一样正常定义
gameLoop(timestamp: number) {
  this.draw();
  window.requestAnimationFrame(this.gameLoop);
}

这三种方法都能解决你的问题,其中方法1(箭头函数)在TypeScript里最常用,语法也最简洁;方法3的绑定操作只需要做一次,性能上也更友好。你可以根据自己的代码风格选择合适的方式。

内容的提问来源于stack exchange,提问作者nishi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 18:42:50