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访问器属性并序列化:
- 首先执行命令生成自定义管道:
ng generate pipe pipes/customJson - 编写管道逻辑:
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); } }
- 在模板中替换原有管道调用即可:
{{ 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
相关产品推荐
相关产品推荐

