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

Angular使用json管道序列化类实例时丢失get属性如何处理?

问题原因

Angular内置的json管道底层依赖原生JSON.stringify()方法实现序列化,该方法默认只会序列化对象自身的可枚举实例属性,而你在类中定义的subTotal、taxTotal、grandTotal属于挂载在类原型上的get访问器,默认不会被JSON.stringify()识别遍历,因此序列化结果中不会包含这些属性。

解决方案

方案1:在类中添加自定义toJSON方法(最推荐)

JSON.stringify()执行时会优先调用目标对象的toJSON()方法,序列化该方法的返回结果。你只需要在CheckoutInfo类中新增该方法即可,无需修改其他业务代码:

export class CheckoutInfo {
    lines: CheckoutInfoLine[];
    taxRate: number;

    get subTotal(): number {
        return this.lines.reduce((acc: number, cur: CheckoutInfoLine) => acc + cur.total, 0)
    };

    get taxTotal(): number {
        return this.subTotal * this.taxRate;
    }

    get grandTotal(): number {
        return this.subTotal * (1 + this.taxRate);
    }

    constructor(lines: CheckoutInfoLine[] = [], taxRate: number = 0.7) {
        this.lines = lines;
        this.taxRate = taxRate;
    }

    // 新增自定义序列化方法
    toJSON() {
        return {
            lines: this.lines,
            taxRate: this.taxRate,
            subTotal: this.subTotal,
            taxTotal: this.taxTotal,
            grandTotal: this.grandTotal
        }
    }
}

修改完成后原有模板代码{{ myObject | json }}无需调整,即可输出包含get访问器属性的序列化结果。

方案2:自定义全局JSON管道(适合多类通用场景)

如果你有多个类都存在类似需求,不想逐个修改类定义,可以自己实现一个自定义管道替代Angular内置的json管道,自动识别所有get访问器属性并序列化:

  1. 首先执行命令生成自定义管道:
    ng generate pipe pipes/customJson
  2. 编写管道逻辑:
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'customJson',
  standalone: true // 如果你的项目是Angular14+的standalone模式需要加这个,否则删除即可
})
export class CustomJsonPipe implements PipeTransform {
  transform(value: unknown, indent: number = 2): string {
    // 非对象类型直接序列化
    if (typeof value !== 'object' || value === null || Array.isArray(value)) {
      return JSON.stringify(value, null, indent);
    }
    // 遍历自身及原型链上的所有属性,提取get访问器返回值
    const serialized: Record<string, any> = {};
    let currentProto = value;
    while (currentProto !== Object.prototype) {
      Object.getOwnPropertyNames(currentProto).forEach(key => {
        const descriptor = Object.getOwnPropertyDescriptor(currentProto, key);
        // 跳过方法,只保留属性和get访问器
        if (descriptor && (descriptor.get || typeof descriptor.value !== 'function')) {
          serialized[key] = (value as any)[key];
        }
      });
      currentProto = Object.getPrototypeOf(currentProto);
    }
    return JSON.stringify(serialized, null, indent);
  }
}
  1. 在模板中替换原有管道调用即可:
    {{ myObject | customJson }}

方案3:构造函数显式赋值(不推荐,仅适合静态对象)

如果你确定类实例创建后属性不会再更新,可以在构造函数中将get访问器的返回值显式赋值给实例自身的属性:

constructor(lines: CheckoutInfoLine[] = [], taxRate: number = 0.7) {
    this.lines = lines;
    this.taxRate = taxRate;
    // 显式赋值为实例属性
    this.subTotal = this.subTotal;
    this.taxTotal = this.taxTotal;
    this.grandTotal = this.grandTotal;
}

该方案的缺点是赋值后属性值固定,后续lines或taxRate更新时,这些属性不会自动同步最新值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:12:04