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

Three.js requestAnimationFrame调用类方法报undefined错误如何解决

错误原因

该报错的本质是JavaScript函数执行上下文(this)丢失:

  • ES 类的方法默认运行在严格模式下,当你将this.animate作为回调传入requestAnimationFrame时,实际是把类原型上的animate方法脱离实例单独传递,方法被requestAnimationFrame调度执行时,内部的this不再指向类实例,会变为undefined。执行到方法内requestAnimationFrame(this.animate)这行时,尝试读取undefined的animate属性,就会抛出题目中的类型错误。
  • 现有代码还存在三个会导致后续运行异常的隐藏问题:
    • 给window绑定resize事件时传入的this.onWindowResize同样存在this丢失问题,事件触发时回调内的this会指向window对象,而非类实例
    • onWindowResize方法内直接使用camera、renderer变量,没有通过this访问实例上的属性,就算this绑定正确也会触发变量未定义的错误
    • 现有代码没有主动调用animate方法的逻辑,就算修复了this问题,渲染循环也不会自动启动
修复方案

以下两种方案可任选其一实现修复:

方案1:构造函数内手动绑定this(兼容性最佳)

在构造函数中通过bind方法强制将回调函数的this固定到当前类实例,同时修正resize回调的属性访问逻辑,补全渲染循环启动调用:

export class BEngine
{
    constructor(doc){
        // 固定回调方法的this指向当前实例
        this.animate = this.animate.bind(this);
        this.onWindowResize = this.onWindowResize.bind(this);

        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        doc.body.appendChild(this.renderer.domElement);
        window.addEventListener("resize", this.onWindowResize, false);
        // 启动渲染循环
        this.animate();
    }
    animate() 
    {
        requestAnimationFrame(this.animate);
        this.renderer.render(this.scene, this.camera);
    }
    onWindowResize() {
        // 通过this访问实例属性
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
}

方案2:箭头函数定义回调方法(写法更简洁)

箭头函数没有自身的this上下文,会直接继承定义位置外层的this(即类实例),从根源避免this丢失问题:

export class BEngine
{
    constructor(doc){
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        doc.body.appendChild(this.renderer.domElement);
        window.addEventListener("resize", this.onWindowResize, false);
        // 启动渲染循环
        this.animate();
    }
    // 箭头函数定义方法,固定this指向实例
    animate = () => {
        requestAnimationFrame(this.animate);
        this.renderer.render(this.scene, this.camera);
    }
    onWindowResize = () => {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 08:51:29