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

JS子类声明字段后用this访问报错,如何正确使用子类字段?

问题描述

在JavaScript子类中声明字段后,使用this访问时出现错误,尝试箭头函数也无法解决。

简化示例代码

class Shape {}

class Polygon extends Shape {
  name;
  constructor() {
    this.name = 'Polygon';
  }

  cout() {
    console.log(this.name);
  }
}

const poly1 = new Polygon();
poly1.cout(); // 返回错误
// 预期输出: "Polygon"

实际业务代码

class TankScene extends Scene
{
    tank1;
    collidables;

    buildScene()
    {
        super.buildScene();
        this.collidables = [];

        this.tank1 = new ControllableTank(SpriteTypes.blueTank);
        this.floor = new GameObject("Floor", ModelTypes.plane, SpriteTypes.woodenFloor);


        this.tank1.tankBody.uniformSetScale(5);
        this.floor.uniformSetScale(10);

        this.collidables.push(this.tank1.tankBody);

        this.addChild(this.tank1);
        this.addChild(this.floor);

        this.tank1.setCollidables(this.collidables);
    }

    doUpdate() {
        super.doUpdate();
        console.log(this.tank1);
    }

}

不声明tank1和collidables字段时,日志能输出预期值,但声明后就会出错,请问问题出在哪里?


问题分析与解决

简化示例的核心问题

你的简化代码直接报错的原因很明确:JavaScript子类的构造函数中,必须先调用super()才能访问this。不管父类有没有显式构造函数,只要子类定义了构造函数,就必须先执行super()完成父类初始化,才能操作子类的this。

修改后的简化代码:

class Shape {}

class Polygon extends Shape {
  name;
  constructor() {
    super(); // 必须先调用super()
    this.name = 'Polygon';
  }

  cout() {
    console.log(this.name);
  }
}

const poly1 = new Polygon();
poly1.cout(); // 正常输出: "Polygon"

实际业务代码的问题

结合你描述的“不声明字段正常,声明后出错”的现象,大概率是以下两种情况之一:

情况1:父类构造函数提前调用了子类方法

如果父类Scene的构造函数中调用了buildScene或doUpdate,子类字段的初始化时机就会引发问题:
JavaScript类字段的执行顺序是:先调用super()(执行父类构造)→ 初始化子类字段(赋值undefined)→ 执行子类构造的自定义代码。
如果父类构造里调用了buildScene,此时子类字段已经被初始化为undefined,但你在buildScene里的赋值逻辑还没执行,就会导致后续访问this.tank1时拿到undefined。

情况2:方法的this指向丢失

如果doUpdate或buildScene是被当作回调函数(比如定时器、事件监听)调用的,this会脱离实例上下文,变成window(非严格模式)或undefined(严格模式):
不声明字段时,可能父类的绑定逻辑让this保持正确;但声明字段后,类字段是实例的自有属性,this指向错误时访问this.tank1就会报错或返回undefined。

解决方法

  • 把方法改成箭头函数,强制this始终指向实例:
class TankScene extends Scene
{
    tank1;
    collidables;

    buildScene = () => {
        // 原代码逻辑不变
    }

    doUpdate = () => {
        super.doUpdate();
        console.log(this.tank1);
    }
}
  • 或者在子类构造函数中手动绑定this:
class TankScene extends Scene
{
    tank1;
    collidables;

    constructor() {
        super();
        this.buildScene = this.buildScene.bind(this);
        this.doUpdate = this.doUpdate.bind(this);
    }

    // 原方法逻辑不变
}

额外排查点

  • 检查父类Scene是否有同名的tank1或collidables字段,子类声明的字段会覆盖父类同名属性,可能引发逻辑冲突。
  • 确认代码运行环境支持ES2022+的类字段语法,旧环境需要用Babel转译,否则字段声明会触发语法错误中断代码执行。

内容的提问来源于stack exchange,提问作者The Good Goomba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:17:17