将带有符号的 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; 


对象被操作后,我需要将PUTPOST返回给服务器。但看起来AureliaHttpClient 正在发送一个空的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的主要内容,如果未能解决你的问题,请参考以下文章

java实体类怎么转换成json。

springmvc 枚举类转json

React/Reflux:使用装饰器将带有 mixin 的类转换为 ES6

C# 实体类转json数据过滤掉字段为null的字段

使用Gson将对象类转成Json对象时出现u003d的问题

java net.sf.json 如何将javabean的首字母转换为大写