Javascript 将带有符号的ES6类转换为JSON
我有硬编码类来表示我的Aurelia应用程序中的模型。这是一个“后期编辑”模型:Javascript 将带有符号的ES6类转换为JSON,javascript,json,ecmascript-6,aurelia,Javascript,Json,Ecmascript 6,Aurelia,我有硬编码类来表示我的Aurelia应用程序中的模型。这是一个“后期编辑”模型: var _postID = Symbol(); var _title = Symbol(); var _text = Symbol(); export class PostEdit { constructor(postEdit) { this[_postID] = postEdit.postID; this.title = postEdit.title;
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; }
}
操作对象后,我需要将其放回服务器,然后将其放回服务器。但是它看起来像是Aurelia
的HttpClient
正在发送一个空的JSON
字符串({}
)。仔细观察,在将ES6类转换为JSON
时,似乎忽略了符号
如何将我的所有属性放入JSON
字符串以提交回服务器?我假设您使用符号来保持数据的私有性,但这意味着您必须执行一些额外的步骤,如果您希望数据包含在JSON表示中
下面是一个在模型上使用toJSON
显式导出您关心的属性的示例
export class PostEdit {
// ...
toJSON() {
return {
postID: this.postID,
title: this.title,
text: this.text
};
}
}
或
在您的实例上调用JSON.stringify
时,它将自动调用toJSON
为您的类指定一个toJSON
方法,该方法返回可stringify的对象:
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
};
}
}
将自动调用该函数并用结果替换您的实例
另外,您可能希望向类中添加一个fromJSON
方法,可以在JSON.parse
期间使用该方法来恢复实例。在您的情况下,这是微不足道的:
static fromJSON(obj) {
return new this(obj);
}
但在其他类中可能需要更复杂的东西。基于符号的私有变量是ES6中封装的一个重要方法。JS中的封装很少是合理的,但是这些是导致问题的访问器(不是符号)
访问器在ES6类中。因此,属性不是在实例上定义的,而是在原型上定义的,它是不可枚举的。它可以在传输代码中看到,或者通过检查
postEditInstance.hasOwnProperty('postID') === false
Object.getPrototypeOf(postEditInstance).hasOwnProperty('postID') === true
Object.getPrototypeOf(postEditInstance).propertyIsEnumerable('postID') === false
另一方面,stringify
,序列化对象
解决方案是使用方法根据所需的条件序列化对象。或者在模型的访问器上使用Occam的razor,特别是在它们不是关键的情况下。我想使用object.assign将整个类分配给一个对象。
我最初的观点是在将分配的类分配给对象的类上使用它。这在chrome中为\u json
创建了一个无限循环。坏主意
class test {
constructor() {
this._json = {type: 'map'};
Object.assign(this, this._json);
}
toJSON(){
Object.assign(this._json, this);
return this._json;
}
}
我必须排除\ujson
变量,所以我迭代类变量以排除它
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!==''ujson')
尚未对其进行全面测试,但我认为这将是一个很好的共享。要获得更动态的解决方案,请使用以下内容:
export class MeMe(){
toJSON() {
return Object.getOwnPropertyNames(this).reduce((a, b) => {
a[b] = this[b];
return a;
}, {});
}
}
或者您可以使用我的:)
您希望它们在JSON表示中是什么样子?JSON对象属性看起来像“name”:“value”
,但是符号应该使用什么名称呢?有关JSON中可以表示的值的类型,请参见www.JSON.org。您可能需要在类中提供一个toJSON
方法来返回所需的表示形式。@Barmar最后我需要{“postID”:“1”…}
。我想我希望有一些内在的方法来做到这一点,为什么你需要接球手和二传手?他们不会做任何事情,除非你使用普通财产。@Jonesopolis:绝对是过火了。如果在getter/setter主体中添加验证或解析或其他内容,则可以使用它们,但如果只是分配/访问“更私有”的属性,则几乎没有用处。顺便说一句,符号不是私有的,它们只是隐藏在普通循环或类似于JSON.stringify
的东西中不被枚举。他们仍然可以被任何人访问。优雅的解决方案。
export class MeMe(){
toJSON() {
return Object.getOwnPropertyNames(this).reduce((a, b) => {
a[b] = this[b];
return a;
}, {});
}
}
import json from "json-decorator";
@json("postID") // pass the property names that you want to ignore
export class MeMe(){
// ...
}