将带有符号的 ES6 类转换为 JSON
Posted
技术标签:
【中文标题】将带有符号的 ES6 类转换为 JSON【英文标题】:Convert ES6 Class with Symbols to JSON 【发布时间】:2016-01-27 17:56:37 【问题描述】:我有硬编码的类来表示我的 Aurelia 应用程序中的模型。这是一个模型“PostEdit”:
var _postID = Symbol();
var _title = Symbol();
var _text = Symbol();
export class PostEdit
constructor(postEdit)
this[_postID] = postEdit.postID;
this.title = postEdit.title;
this.text= postEdit.text;
get postID() return this[_postID];
get title() return this[_title];
set title(val) this[_title] = val;
get text() return this[_text];
set text(val) this[_text] = val;
对象被操作后,我需要将PUT
和POST
返回给服务器。但看起来Aurelia
的HttpClient
正在发送一个空的JSON
字符串()。调查一下,在将 ES6 类转换为
JSON
时,似乎忽略了 Symbols
。
如何将我的所有属性放入JSON
字符串以提交回服务器?
【问题讨论】:
您希望它们在 JSON 表示中看起来像什么? JSON 对象属性看起来像"name": "value"
,但是应该为 Symbol
使用什么名称?
查看 www.json.org 了解可以用 JSON 表示的值的类型。您可能需要在您的类中提供 toJSON
方法以返回所需的表示形式。
@Barmar 最后我需要 "postID": "1" ...
。我想我希望有一些内置的方法来做到这一点
为什么需要getter和setter?除了使用普通属性时,它们不会做任何事情。
@Jonesopolis:绝对是矫枉过正。如果您在 getter/setter 主体中添加验证或解析或其他任何内容,则可以使用它们,但如果您只是分配/访问“更私有”的属性,它几乎没有用处。顺便说一句,符号不是私有的,它们只是被隐藏在正常循环或JSON.stringify
之类的东西中被枚举。任何想要访问的人仍然可以访问它们。
【参考方案1】:
我假设您使用符号来保持数据的私密性,但这意味着如果您希望将数据包含在 JSON 表示中,您将不得不执行一些额外的步骤。
这是一个在您的模型上使用toJSON
来显式导出您关心的属性的示例
export class PostEdit
// ...
toJSON()
return
postID: this.postID,
title: this.title,
text: this.text
;
或者
export class PostEdit
// ...
toJSON()
let postID, title, text = this;
return postID, title, text;
当你的实例调用JSON.stringify
时,它会自动调用toJSON
【讨论】:
【参考方案2】:给你的类一个 toJSON
方法,它返回一个可字符串化的对象:
export class PostEdit
constructor(postEdit)
this[_postID] = postEdit.postID;
this.title = postEdit.title;
this.text = postEdit.text;
get postID() return this[_postID];
get title() return this[_title];
set title(val) this[_title] = val;
get text() return this[_text];
set text(val) this[_text] = val;
toJSON()
return
postId: this.postId,
title: this.title,
text: this.text
;
JSON.stringify
将自动调用它并用结果替换您的实例。
此外,您可能希望在您的类中添加一个fromJSON
方法,您可以使用该方法在JSON.parse
期间恢复实例。在你的情况下这是微不足道的:
static fromJSON(obj)
return new this(obj);
但您可能需要在其他类中使用更复杂的东西。
【讨论】:
【参考方案3】:基于符号的私有变量是 ES6 中封装的重要方法。 JS 中的封装很少被证明是合理的,但这些是访问器(不是符号),在这里会引起问题。
访问器在 ES6 类中是 prototype methods。所以属性不是在实例上而是在原型上定义的,它是不可枚举的。可以在转译的代码中看到,也可以通过查看
postEditInstance.hasOwnProperty('postID') === false
Object.getPrototypeOf(postEditInstance).hasOwnProperty('postID') === true
Object.getPrototypeOf(postEditInstance).propertyIsEnumerable('postID') === false
另一方面,JSON.stringify
序列化对象的only own enumerable properties。
解决方法是使用toJSON方法,根据需要的条件对对象进行序列化。或者在模型的访问器上使用奥卡姆剃刀,特别是如果它们在那里并不重要。
【讨论】:
【参考方案4】:我希望使用Object.assign
将整个类分配给一个对象
我对在将分配的类分配给对象的类上使用它的最初看法。这为 chrome 中的_json
创建了一个无限循环。坏主意。
class test
constructor()
this._json = type: 'map';
Object.assign(this, this._json);
toJSON()
Object.assign(this._json, this);
return this._json;
我不得不排除 _json
变量,所以我遍历了类变量以排除它。
class test2
constructor()
this._json = type: 'map';
Object.assign(this, this._json);
toJSON()
Object.assign(this._json,
conv()
let ret = ;
for(let i in this )
if(i !== '_json')
ret[i] = this[i];
return ret;
);
return this._json;
但奇怪的是,即使没有if(i !== '_json')
,_json
也会被忽略
还没有完全测试过,但我认为这将是一个很好的分享。
【讨论】:
【参考方案5】:更多动态解决方案使用这个:
export class MeMe()
toJSON()
return Object.getOwnPropertyNames(this).reduce((a, b) =>
a[b] = this[b];
return a;
, );
或者你可以使用我的json-decorator :)
import json from "json-decorator";
@json("postID") // pass the property names that you want to ignore
export class MeMe()
// ...
【讨论】:
优雅的解决方案。【参考方案6】:如何将我的所有(符号)属性转换为 JSON 字符串以提交回服务器?
要获取所有符号属性,您可以使用Object.getOwnPropertySymbols() 获取直接在给定对象上找到的所有符号属性的数组。如:
const pe = new PostEdit(...);
const symbols = Object.getOwnPropertySymbols(pe);
但是,由于 PostEdit 的三个符号属性都使用空描述(new Symbol()
,没有任何描述参数),因此无法区分这三个符号。如果上面的symbols
数组打印出来,你会得到:
//console.log(symbols)
[ Symbol(), Symbol(), Symbol() ]
因此,如果您想序列化/反序列化 PostEdit 实例而不向 PostEdit
类添加 toJSON()
/fromJSON()
方法,您可以为符号提供有意义的描述,然后相应地序列化它们:
var _postID = Symbol('postID');
var _title = Symbol('title');
var _text = Symbol('text');
export class PostEdit
...
const pe = new PostEdit(...);
const symbols = Object.getOwnPropertySymbols(pe);
const serializeObj = ;
for (let s of symbols)
serializeObj[s.description] = pe[s];
const serializedText = JSON.stringify(serializeObj);
为了使上述序列化/反序列化步骤更方便使用,并修复相同符号描述的问题,我制作了一个名为 esserializer 的 npm 模块,并在其专业版中实现了这些逻辑。
【讨论】:
以上是关于将带有符号的 ES6 类转换为 JSON的主要内容,如果未能解决你的问题,请参考以下文章