Javascript 将带有符号的 ES6 类转换为 JSON

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33382939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:00:40  来源:igfitidea点击:

Convert ES6 Class with Symbols to JSON

javascriptjsonecmascript-6aurelia

提问by Jonesopolis

I have hardcoded classes to represent models in my Aurelia application. Here's a model 'PostEdit':

我有硬编码的类来表示我的 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; }

}

After the object is manipulated, I need to PUTand POSTit back to the server. But it looks like Aurelia's HttpClientis sending an empty JSONstring ({}). Looking into it, it seems that Symbolsare ignored when converting an ES6 class to JSON.

该对象被操纵后,我需要PUTPOST它回服务器。但看起来Aurelia'sHttpClient正在发送一个空JSON字符串 ( {})。调查它,似乎Symbols在将 ES6 类转换为JSON.

How can I go about getting all my properties into a JSONstring to submit back to the server?

如何将我的所有属性放入一个JSON字符串中以提交回服务器?

回答by Thank you

I'm assuming you're using symbols to keep the data private, but this means you're going to have to go through some extra steps if you want that data included in the JSON representation.

我假设您使用符号来保持数据的私密性,但这意味着如果您希望将数据包含在 JSON 表示中,您将不得不执行一些额外的步骤。

Here's an example using toJSONon your model to explicitly export the properties you care about

这是toJSON在您的模型上使用以显式导出您关心的属性的示例

export class PostEdit {

  // ...
  toJSON() {
    return {
      postID: this.postID,
      title:  this.title,
      text:   this.text
    };
  }
}

Or

或者

export class PostEdit {

  // ...
  toJSON() {
    let {postID, title, text} = this;
    return {postID, title, text};
  }
}

When JSON.stringifyis called on your instance, it will automatically call toJSON

JSON.stringify在您的实例上调用时,它会自动调用toJSON

回答by Fareed Alnamrouti

for more dynamic solution use this:

对于更动态的解决方案,请使用:

export class MeMe(){
 toJSON() {
    return Object.getOwnPropertyNames(this).reduce((a, b) => {
      a[b] = this[b];
      return a;
    }, {});
  }
}

or you can use my json-decorator:)

或者你可以使用我的json-decorator:)

import json from "json-decorator";  

@json("postID") // pass the property names that you want to ignore
export class MeMe(){
  // ...
}

回答by Bergi

Give your class a toJSONmethod that returns a stringifyable object:

为您的类提供一个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.stringifywill automatically call that and replace your instance with the result.

JSON.stringify将自动调用它并用结果替换您的实例。

Also you might want to add a fromJSONmethod to your class that you can use to revive instances during JSON.parse. It is trivial in your case:

此外,您可能希望向fromJSON您的类添加一个方法,您可以使用该方法在JSON.parse. 在你的情况下这是微不足道的:

    static fromJSON(obj) {
        return new this(obj);
    }

but you might need something more complicated in other classes.

但是您可能需要在其他类中更复杂的东西。

回答by Estus Flask

Symbol-based private variables are considerable recipe for encapsulation in ES6. The encapsulation in JS is rarely justified, but these are accessors (not symbols) that cause problems here.

基于符号的私有变量是 ES6 封装的重要方法。JS 中的封装很少被证明是合理的,但这些是导致问题的访问器(而不是符号)。

Accessors are prototype methodsin ES6 classes. So the property is defined not on instance but on prototype, it is non-enumerable. It can be seen in transpiled code, or by checking

访问器是ES6 类中的原型方法。所以属性不是在实例上定义的,而是在原型上定义的,它是不可枚举的。它可以在转译的代码中看到,或者通过检查

postEditInstance.hasOwnProperty('postID') === false
Object.getPrototypeOf(postEditInstance).hasOwnProperty('postID') === true
Object.getPrototypeOf(postEditInstance).propertyIsEnumerable('postID') === false

JSON.stringify, on the other hand, serializes only own enumerable propertiesof the object.

JSON.stringify,另一方面,序列化对象自己的可枚举属性

The solution is to use toJSONmethod to serialize the object according to the desirable conditions. Or to use Occam's razor on model's accessors, especially if they aren't crucial there.

解决方案是使用toJSON方法根据需要的条件序列化对象。或者在模型的配件上使用奥卡姆剃刀,特别是如果它们在那里并不重要。

回答by Martijn Mellens

I wanted to have the whole class assigned to an object using Object.assign

我想将整个班级分配给一个对象使用 Object.assign

My initial perspective on using this on a class assigning the allocated class to object. This created an infinite loop for _jsonin chrome. Bad idea.

我对在将分配的类分配给对象的类上使用它的最初看法。这_json在 chrome 中创建了一个无限循环。馊主意。

class test {
    constructor() {
        this._json = {type: 'map'};
        Object.assign(this, this._json);
    }
    toJSON(){
        Object.assign(this._json, this);
        return this._json;
    }
}

I had to exclude the _jsonvariable, so I iterated over the class variables to exclude it.

我不得不排除_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;
    }
}

but weirdly enough _jsongets ignored even without if(i !== '_json')

但奇怪的是_json即使没有if(i !== '_json')

have not fully tested it, but I thought this would be a good share.

还没有完全测试它,但我认为这将是一个很好的分享。