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

如何在Main类中用this替代全局变量main实现THREE.js动画循环?

How to Replace Global main References with this and Fix requestAnimationFrame Binding Issues

Let's break down how to fix your animation loop problems and cut the dependency on the global main variable:

Core Problem

The key issue here is two-fold:

  1. When you pass main.animate directly to requestAnimationFrame, the function loses its this binding—so subsequent calls end up with this as null (or window in non-strict mode).
  2. Relying on the global main variable makes your code tightly coupled and harder to maintain or reuse.

Step-by-Step Fixes

1. Swap all main references to this in the animate method

First, update every instance of main inside animate() to use this instead. This lets us reference the current class instance directly, no global variable required.

2. Fix this binding for the requestAnimationFrame callback

We need to make sure this stays tied to your Main instance when the browser calls animate for the animation frame. You have three reliable options here:

Option A: Wrap the callback in an arrow function

Arrow functions inherit the this context from their surrounding scope, so wrapping your callback will preserve the correct instance:

requestAnimationFrame(() => this.animate());
Option B: Bind the animate method in the constructor

Add this line to your constructor to permanently bind animate to the instance—this way, no matter how the function is called, this will always point to your Main object:

constructor(idDiv) {
  this.div = document.getElementById(idDiv);
  this.sceneManager = new SceneManager(this.div);
  // Bind animate to the current instance
  this.animate = this.animate.bind(this);
}

With this, you can keep the callback as requestAnimationFrame(this.animate);

Option C: Define animate as a class arrow function

If you're using modern ES6+ syntax, define animate as an arrow function method. This automatically binds this to the instance:

animate = () => {
  console.log('Main::animate::this', this);
  requestAnimationFrame(this.animate);
  this.sceneManager.animate();
}

3. Clean up the execute method call

Your original execute method calls this.animate(main.sceneManager);—since we're now using this.sceneManager inside animate, you don't need to pass the scene manager as an argument. Just call this.animate(); instead.

Full Modified Code

Here's the complete fixed code using Option A (arrow function wrapper) for clarity:

class Main {
  constructor(idDiv) {
    this.div = document.getElementById(idDiv);
    this.sceneManager = new SceneManager(this.div);
  }

  animate() {
    console.log('Main::animate::this', this);
    // Use arrow function to preserve this binding
    requestAnimationFrame(() => this.animate());
    // Replace main with this for sceneManager access
    this.sceneManager.animate();
  }

  execute() {
    new ManageEvents(this.div, this.sceneManager);
    const atla = new Atla();
    const repository = new Repository();
    const loadData = new LoadData(atla, repository);
    loadData.load(this.sceneManager);
    console.log('Main::execute::this', this);
    // No need to pass sceneManager anymore
    this.animate();
  }
}

const main = new Main('original');
main.execute();

Why Your Previous Attempts Failed

  • requestAnimationFrame(main.animate(main)): This immediately runs main.animate(main) and passes its return value (which is undefined) to requestAnimationFrame—hence the "callback is not a function" error. It also causes an infinite loop because you're calling animate synchronously over and over.
  • Passing the instance as an argument: Without fixing the this binding, even if you pass main as a parameter, the function's internal this would still be null in subsequent animation frame calls.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:38:49