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

TypeScript静态方法访问prototype undefined 游戏实体序列化问题

问题根源

存在两个核心问题:

  1. this指向丢失:注册实体时直接传递XWingEntity.create,该方法被取出后作为独立函数调用,严格模式下this默认指向undefined,自然无法读取到prototype属性。
  2. 逻辑错误:原代码直接对this.prototype执行Object.assign会修改类的原型对象,所有该类的实例都会被本次赋值的参数影响,完全不符合创建单个实例的需求。
修复方案

1. 修正create静态方法逻辑

不要修改原型,改为创建独立的新实例:

static create(registryName: string, args: Record<string, any>) {
    // 创建继承自当前类原型的空实例,保证实例能调用类的成员方法(如tick)
    const object = Object.create(this.prototype);
    // 将参数赋值给新实例而非原型
    Object.assign(object, args);
    // 兼容直接传x、y的场景,自动组装vec属性
    if (!object.vec && args.x !== undefined && args.y !== undefined) {
        object.vec = {x: args.x, y: args.y};
    }
    object.registryName = registryName;
    return object as IGameEntity;
}

如果希望走构造函数初始化更规范,也可以改写为:

static create(registryName: string, args: Record<string, any>) {
    const instance = new this(
        args.vec ?? {x: args.x ?? 0, y: args.y ?? 0}, 
        args.rotation ?? 0, 
        args.scale ?? 1
    );
    instance.registryName = registryName;
    // 批量赋值其他自定义属性
    Object.assign(instance, args);
    return instance;
}

2. 修复注册时的this指向

注册实体时给create方法绑定正确的this指向,保证调用时this指向对应子类:

register(){
    // 方案1:用bind绑定this为XWingEntity
    this.reg(EntityRegistry.ENTITY_X_WING, XWingEntity.create.bind(XWingEntity));
    // 方案2:用箭头函数包裹,固定this指向
    // this.reg(EntityRegistry.ENTITY_X_WING, (name, args) => XWingEntity.create(name, args));
}

3. 补充类型定义修正

你的EntityRegistry里的entities属性实际是作为键值对对象使用,不是数组,修正定义避免TS报错:

// 替换原数组类型定义
entities: Record<string, (registryName: string, data: {}) => IGameEntity> = {};
优化建议

如果不想手动维护注册、赋值逻辑,可以引入class-transformer工具库,直接实现类实例和JSON的双向转换,自动补全类方法和类型,不用手动写create逻辑。如果希望轻量化不引入额外依赖,以上修改后的方案已经可以稳定运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 19:45:05