将 JSON.stringify 与 TypeScript getter/setter 结合使用
Posted
技术标签:
【中文标题】将 JSON.stringify 与 TypeScript getter/setter 结合使用【英文标题】:Using JSON.stringify in conjunction with TypeScript getter/setter 【发布时间】:2017-02-26 02:07:00 【问题描述】:我在 TypeScript 中使用 getter/setter 访问器。由于变量和方法不可能有相同的名称,因此我开始在变量前面加上一个低破折号,就像在许多示例中所做的那样:
private _major: number;
get major(): number
return this._major;
set major(major: number)
this._major = major;
现在当我使用 JSON.stringify() 方法将对象转换为 JSON 字符串时,它将使用变量名作为键:_major。
由于我不希望 JSON 文件的所有键都以低破折号为前缀,因此是否有可能使 TypeScript 使用 getter 方法的名称(如果可用)?或者有没有其他方法可以使用 getter/setter 方法但仍能产生干净的 JSON 输出?
我知道有一些方法可以在将 JSON 键写入字符串输出之前手动修改它们。我很好奇是否有更简单的解决方案。
Here is a JSFiddle 演示当前行为。
【问题讨论】:
我假设另一种方法是使用属性的大写,例如get Major()... 类似于 C# 的属性命名约定 【参考方案1】:不,您不能让 JSON.stringify
使用 getter/setter 名称而不是属性名称。
但你可以这样做:
class Version
private _major: number;
get major(): number
return this._major;
set major(major: number)
this._major = major;
toJsonString(): string
let json = JSON.stringify(this);
Object.keys(this).filter(key => key[0] === "_").forEach(key =>
json = json.replace(key, key.substring(1));
);
return json;
let version = new Version();
version.major = 2;
console.log(version.toJsonString()); // "major":2
【讨论】:
参考以下答案,您可以在对象上定义一个 toJSON 函数,该函数会自动被 JSON.stringify(yourclassobject) ***.com/questions/29705211/… 使用 @N15M0_jk 是的,确实如此,但我不想“覆盖”JSON.stringify
的行为,而只是使用 version.toJsonString()
这会产生错误:TypeError: myObject.toJsonString is not a function
@TeodorKolev 我刚刚在打字稿操场上检查了这个确切的代码,效果很好。
使用toJSON
。出于某种原因,没有人绝对应该使用toJSON
或valueOf
。我想没有多少人知道这些存在。例如,class User ...
可以利用方法valueOf() return this.id;
,因此它可以用作var id = +user;
。不确定这是否为您提供了更多的筹码。【参考方案2】:
我认为遍历属性和字符串操作是危险的。我会使用对象本身的原型,如下所示:
public static toJSONString() : string
return JSON.stringify(this, Object.keys(this.constructor.prototype)); // this is version class
【讨论】:
这是有效的,但它只返回 setter 和 getter。如何获取不是 getter 和 setter 的所有其他属性?【参考方案3】:基于@Jan-Aagaard 解决方案我已经测试了这个
public toJSON(): string
let obj = Object.assign(this);
let keys = Object.keys(this.constructor.prototype);
obj.toJSON = undefined;
return JSON.stringify(obj, keys);
为了使用 toJSON 方法
【讨论】:
为了得到完整的对象,我用 let keys = Object.keys(this).concat(Object.keys(this.constructor.prototype)) 代替 这是正确的答案。但我认为您不需要obj.toJSON = undefined;
行,因为 JSON.stringify
完全忽略了方法。如果我不正确,请告诉我。
@Cody 是的,它忽略了序列化方法,但是如果toJSON
方法仍然定义,它将调用它而不是直接序列化对象,这会产生一个递归的永恒循环。您需要“取消定义”toJSON
以避免这种情况。【参考方案4】:
我编写了一个小型库 ts-typed,它为运行时类型生成 getter/setter。我在使用 JSON.stringify() 时遇到了同样的问题。所以我通过添加一种序列化程序来解决它,并建议实现一种 toString(在 Java 中)购买调用它 toJSON。
这是一个例子:
import TypedSerializer from 'ts-typed';
export class RuntimeTypedClass
private _major: number;
get major(): number
return this._major;
set major(major: number)
this._major = major;
/**
* toString equivalent, allows you to remove the _ prefix from props.
*
*/
toJSON(): RuntimeTypedClass
return TypedSerializer.serialize(this);
【讨论】:
【参考方案5】:旧问题的新答案。对于 getter/setter 没有私有字段,或者私有字段名称与 getter/setter 不同的情况,我们可以使用 Object.getOwnPropertyDescriptors
从原型中找到 get
方法。
https://***.com/a/60400835/2325676
我们在这里添加了toJSON
函数,以便它与其他海报提到的JSON.stringify
一起使用。这意味着我们不能在toJSON
中调用JSON.stringify()
,因为它会导致无限循环,所以我们使用Object.assign(...)
进行克隆
我还删除了 _private
字段作为整理措施。您可能希望删除不想包含在 JSON 中的其他字段。
public toJSON(): any
//Shallow clone
let clone: any = Object.assign(, this);
//Find the getter method descriptors
//Get methods are on the prototype, not the instance
const descriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(this))
//Check to see if each descriptior is a get method
Object.keys(descriptors).forEach(key =>
if (descriptors[key] && descriptors[key].get)
//Copy the result of each getter method onto the clone as a field
delete clone[key];
clone[key] = this[key]; //Call the getter
);
//Remove any left over private fields starting with '_'
Object.keys(clone).forEach(key =>
if (key.indexOf('_') == 0)
delete clone[key];
);
//toJSON requires that we return an object
return clone;
【讨论】:
【参考方案6】:不是动态的,但它可以工作
export class MyClass
text: string
get html()
return this.text.toString().split("\n").map(e => `<p>$e</p>`).join('');
toJson(): string
return JSON.stringify( ...this, html: this.html )
通话中
console.log(myClassObject.toJson())
【讨论】:
以上是关于将 JSON.stringify 与 TypeScript getter/setter 结合使用的主要内容,如果未能解决你的问题,请参考以下文章
关于JSON.stringify()与JSON.parse()
JSON.stringify与jQuery.parseJSON