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

TypeScript类内this访问属性与外部实例属性值不一致问题

问题根因

这个问题和decimal.js类型无关,核心原因是你将toDto写成了类实例字段形式的箭头函数,结合项目中常见的对象代理/包装逻辑(Vue3/MobX响应式、ORM实体包装、immer不可变更新、class-transformer等序列化工具都有这类逻辑),导致this指向和你外部观测的实例不一致:

  • 类字段箭头函数会在构造函数执行阶段,为每个实例单独创建一个函数,这个函数的this会被永久绑定到刚创建的原始未包装实例上,无法被后续的代理、bind、call修改。
  • 当实例被上述工具处理后,你在外部断点观测到的实际是原始实例的代理/包装对象,看到的currentBalance=2957.86是代理对象上的属性值,原始实例上的该属性还停留在初始化时的0。
  • 调用代理对象的toDto方法时,由于代理本身没有重写该方法,会找到原始实例上绑定的箭头函数执行,此时this指向原始实例,自然读到的是0值。
  • 你将实例作为source参数传入时,访问的是传入的代理对象本身的属性,因此能拿到正确值。

另外你当前构造函数的判断逻辑存在隐性bug:用if (xxx.currentBalance)做判断时,合法的0值会被判定为false,错误走默认赋值逻辑。

标准修复方案

将箭头函数形式的类字段方法改为定义在原型上的普通类方法即可。普通类方法的this是调用时动态绑定的,谁调用方法this就指向谁,在代理对象上调用时会正确指向代理对象,读到最新的属性值:

export class LedgerAccount {
    currentBalance: Decimal;
    
    constructor(request: CreateLedgerAccountRequest | LedgerAccountDto) {
        // 修复原判断的0值误判问题
        if ((request as LedgerAccountDto).currentBalance !== undefined) {
            this.currentBalance = new Decimal((request as LedgerAccountDto).currentBalance);
        } else {
            this.currentBalance = new Decimal(0);
        }
    }

    // 改为普通原型方法,不要用箭头函数赋值
    toDto(): LedgerAccountDto {
        const result: LedgerAccountDto = {
            currentBalance: this.currentBalance.toNumber(),
        };
        return result;
    }
}

如果确实有固定this的需求(比如需要把方法直接作为回调传递,避免丢失this),可以在构造函数中显式绑定,而不是用类字段箭头函数:

constructor(request: CreateLedgerAccountRequest | LedgerAccountDto) {
    // ...原有初始化逻辑
    this.toDto = this.toDto.bind(this);
}

注意这种绑定方式如果遇到代理场景依然会有this指向原始对象的问题,非必要不使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.12 16:15:50