将 ES6 类对象序列化为 JSON

     2023-02-15     64

关键词:

【中文标题】将 ES6 类对象序列化为 JSON【英文标题】:Serializing an ES6 class object as JSON 【发布时间】:2017-03-05 05:41:52 【问题描述】:
class MyClass 
  constructor() 
    this.foo = 3
  


var myClass = new MyClass()

我想将myClass 对象序列化为 json。

我能想到的一种简单方法是,因为每个成员实际上都是 javascript 对象(数组等)。我想我可以维护一个变量来保存成员变量。

this.prop.foo = this.foo 等等。

我希望为类对象找到一个 toJSON/fromJSON 库,因为我将它们与其他语言(如 swift/java)一起使用,但找不到用于 javascript 的库。

也许类结构太新,或者我的要求可以在没有库的情况下以某种方式轻松实现。

【问题讨论】:

你听说过JSON.stringify()吗?这符合你的要求吗? 您有这样做的理由吗? @Pineda 是的,我想将可序列化的数据存储在 react redux 存储中。但是,答案似乎表明我可以将我的类对象存储在 redux 中,因为它已经是可序列化的。 相关:反序列化:***.com/questions/38922990/… 【参考方案1】:

与您想在 JS 中字符串化的任何其他对象一样,您可以使用JSON.stringify

JSON.stringify(yourObject);

class MyClass 
  constructor() 
    this.foo = 3
  


var myClass = new MyClass()

console.log(JSON.stringify(myClass));

另外值得注意的是,您可以自定义stringify 如何序列化您的对象,方法是给它一个toJSON method。用于在结果 JSON 字符串中表示您的对象的值将是对该对象调用 toJSON 方法的结果。

【讨论】:

如何反序列化它。 @IWuZuo JSON.parse( string ) 谢谢。 JSON.parse(string) 返回一个 json 对象。不是 MyClass 的实例。 @IWuZhuo 为此,我建议您在类上创建一个静态方法,该方法接受该对象并通过创建具有 JSON 中属性的对象来返回该类的实例。开箱即用的 Javascript 无法做到这一点,但我会说自己编写很容易 要反序列化,它并不是那么简单,尤其是在涉及复杂的嵌套对象时,但是有一个轻量级库可以做到这一点。详情请查看我的回答。【参考方案2】:

我知道这个问题已经很老了,但我一直在睁大眼睛,直到我写了一个紧凑的、真实的、“安全的”解决方案。

反序列化返回仍然具有附加工作方法的对象。

您唯一需要做的就是在序列化器的构造函数中注册要使用的类。


class Serializer
    constructor(types)this.types = types;
    serialize(object) 
        let idx = this.types.findIndex((e)=> return e.name == object.constructor.name);
        if (idx == -1) throw "type  '" + object.constructor.name + "' not initialized";
        return JSON.stringify([idx, Object.entries(object)]);
    
    deserialize(jstring) 
        let array = JSON.parse(jstring);
        let object = new this.types[array[0]]();
        array[1].map(e=>object[e[0]] = e[1];);
        return object;
    


class MyClass 
    constructor(foo) this.foo = foo;
    getFoo()return this.foo;


var serializer = new Serializer([MyClass]);

console.log(serializer.serialize(new MyClass(42)));
//[0,[["foo",42]]]

console.log(serializer.deserialize('[0,[["foo",42]]]').getFoo());
//42

以上内容应该足以让您继续前进,但可以找到更多详细信息和缩小版here。

【讨论】:

此示例不处理递归对象初始化。如果类Person包含成员Address,反序列化后你将无法调用Address的方法。【参考方案3】:

我遇到过这个库,它可以对复杂对象(包括嵌套对象和数组)进行序列化和反序列化:

https://github.com/typestack/class-transformer

它至少有两种方法:

plainToClass() -> json obj to class
classToPlain() -> class to json obj

【讨论】:

【参考方案4】:

我制作了一个模块esserializer 来解决这个问题。它是一个序列化 JavaScript 类实例的实用程序,并将“序列化文本”反序列化为实例对象,并保留所有类/属性/方法等。

要序列化一个实例,只需调用serialize() 方法:

const ESSerializer = require('esserializer');
let serializedString = ESSerializer.serialize(anObject);

serialize()的内部机制是:将实例的属性及其类名信息递归保存到字符串中。

要从字符串反序列化,只需调用deserialize() 方法,将所有涉及的类作为参数传递:

const ESSerializer = require('esserializer');
const ClassA = require('./ClassA');
const ClassB = require('./ClassB');
const ClassC = require('./ClassC');

let deserializedObj = ESSerializer.deserialize(serializedString, [ClassA, ClassB, ClassC]);

deserialize()的内部机制是:手动组合对象及其原型信息,递归。

【讨论】:

replit.com/@deanc1/SickOblongMicroinstruction#index.js 这适用于一级深层嵌套对象 - 谢谢@shaochuancs【参考方案5】:

如果您不介意将类定义传递给解码,这很容易。

// the code
const encode = (object) => JSON.stringify(Object.entries(object))

const decode = (string, T) => 
  const object = new T()
  JSON.parse(string).map(([key, value]) => (object[key] = value))
  return object


// test the code
class A 
  constructor(n) 
    this.n = n
  

  inc(n) 
    this.n += n
  


const a = new A(1)
const encoded = encode(a)
const decoded = decode(encoded, A)
decoded.inc(2)
console.log(decoded)

【讨论】:

如果您不使用嵌套对象,这是一个很好的解决方案。但是,当您尝试这样做时,您会看到失败:replit.com/@deanc1/PerfumedBustlingAngle#index.js【参考方案6】:

不是一个新话题,但有一个新的解决方案:现代方法(2021 年 12 月)是使用 @badcafe/jsonizer : https://badcafe.github.io/jsonizer

与其他解决方案不同,它不会通过注入的类名污染您的数据, 它重新定义了预期的数据层次结构。 以下是 Typescript 中的一些示例,但在 JS 中也同样有效

在展示一个类的例子之前,让我们从一个简单的数据结构开始:

const person = 
    name: 'Bob',
    birthDate: new Date('1998-10-21'),
    hobbies: [
           hobby: 'programming',
            startDate: new Date('2021-01-01'),
        ,
           hobby: 'cooking',
            startDate: new Date('2020-12-31'),
        ,
    ]

const personJson = JSON.stringify(person);
// 
//     "name": "Bob",
//     "birthDate": "1998-10-21T00:00:00.000Z",
//     "hobbies": [
//         
//             "hobby": "programming",
//             "startDate": "2021-01-01T00:00:00.000Z"
//         ,
//         
//             "hobby": "cooking",
//             "startDate": "2020-12-31T00:00:00.000Z"
//         
//     ]
// 
// store or send the data

请注意,日期被序列化为字符串,如果您解析该 JSON,日期将不会是 Date 实例,它们将是 Strings

现在,让我们使用 Jsonizer ?

// in Jsonizer, a reviver is made of field mappers :
const personReviver = Jsonizer.reviver<typeof person>(
    birthDate: Date,
    hobbies: 
        '*': 
            startDate: Date
        
    
);
const personFromJson = JSON.parse(personJson, personReviver);

JSON 文本中的每个日期字符串都已映射到解析结果中的 Date 对象。

Jsonizer 可以用递归嵌套的自定义类、第三方类、内置类或子 JSON 结构(数组、对象)无差别地恢复 JSON 数据结构(数组、对象)或类实例。

现在,让我们改用一个类:

// in Jsonizer, a class reviver is made of field mappers + an instance builder :
@Reviver<Person>( // ?  bind the reviver to the class
    '.': (name, birthDate, hobbies) => new Person(name, birthDate, hobbies), // ?  instance builder
    birthDate: Date,
    hobbies: 
        '*': 
            startDate: Date
        
    
)
class Person 
    constructor( // all fields are passed as arguments to the constructor
        public name: string,
        public birthDate: Date
        public hobbies: Hobby[]
    ) 

interface Hobby 
    hobby: string,
    startDate: Date


const person = new Person(
    'Bob',
    new Date('1998-10-21'),
    [
           hobby: 'programming',
            startDate: new Date('2021-01-01'),
        ,
           hobby: 'cooking',
            startDate: new Date('2020-12-31'),
        ,
    ]
);
const personJson = JSON.stringify(person);

const personReviver = Reviver.get(Person); // ?  extract the reviver from the class
const personFromJson = JSON.parse(personJson, personReviver);

最后,让我们使用 2 个类:

@Reviver<Hobby>(
    '.': (hobby, startDate) => new Hobby(hobby, startDate), // ?  instance builder
    startDate: Date
)
class Hobby 
    constructor (
        public hobby: string,
        public startDate: Date
    ) 


@Reviver<Person>(
    '.': (name, birthDate, hobbies) => new Person(name, birthDate, hobbies), // ?  instance builder
    birthDate: Date,
    hobbies: 
        '*': Hobby  // ?  we can refer a class decorated with @Reviver
    
)
class Person 
    constructor(
        public name: string,
        public birthDate: Date,
        public hobbies: Hobby[]
    ) 


const person = new Person(
    'Bob',
    new Date('1998-10-21'),
    [
        new Hobby('programming', new Date('2021-01-01')),
        new Hobby('cooking', new Date('2020-12-31')
    ]
);
const personJson = JSON.stringify(person);

const personReviver = Reviver.get(Person); // ?  extract the reviver from the class
const personFromJson = JSON.parse(personJson, personReviver);

【讨论】:

【参考方案7】:

您需要能够递归地重新初始化对象。有一个无参数的构造函数不是必须的,你可以不用它。

这是我执行深层复制的方式:

class Serializer

  constructor(types)
    this.types = types;
  

  markRecursive(object)
  
    // anoint each object with a type index
    let idx = this.types.findIndex(t => 
      return t.name === object.constructor.name;
    );
    if (idx !== -1)
    
      object['typeIndex'] = idx;

      for (let key in object)
      
        if (object.hasOwnProperty(key) && object[key] != null)
          this.markRecursive(object[key]);
      
    
  

  cleanUp(object)
  
    if (object.hasOwnProperty('typeIndex')) 
      delete object.typeIndex;
      for (let key in object) 
        if (object.hasOwnProperty(key) && object[key] != null) 
          console.log(key);
          this.cleanUp(object[key]);
        
      
    
  

  reconstructRecursive(object)
  
    if (object.hasOwnProperty('typeIndex'))
    
      let type = this.types[object.typeIndex];
      let obj = new type();
      for (let key in object)
      
        if (object.hasOwnProperty(key) && object[key] != null) 
          obj[key] = this.reconstructRecursive(object[key]);
        
      
      delete obj.typeIndex;
      return obj;
    
    return object;
  

  clone(object)
  
    this.markRecursive(object);
    let copy = JSON.parse(JSON.stringify(object));
    this.cleanUp(object);
    return this.reconstructRecursive(copy);
  

这个想法很简单:在序列化时,每个已知 类型(this.types 中的类型)的成员都被一个名为typeIndex 的成员涂抹。反序列化后,我们递归地初始化每个有typeIndex的子结构,然后去掉它以避免污染结构。

【讨论】:

javascriptserializer类对象序列化为json,json反序列化为对象

...Web服务器之间传递的数据。说白了就是能够直接将一个C#对象传送到前台页面成为javascript对象。要添加System.Web.Extensions.dll的引用。该类位于System.Web.Script.Serialization命名空间下。一、属性MaxJsonLength获取或设置JavaSc 查看详情

Android:无法使用 Gson 将 json 反序列化为类对象

】Android:无法使用Gson将json反序列化为类对象【英文标题】:Android:CannotdeserializejsonintoclassobjectwithGson【发布时间】:2021-12-0304:41:46【问题描述】:给定下一个json:"alpha_two_code":"AR","web_pages":["http://www.atlantida.edu.ar/"],"name":"Universida... 查看详情

将 JSON 反序列化为对象

】将JSON反序列化为对象【英文标题】:DeserializingJSONintoanobject【发布时间】:2016-03-1707:26:47【问题描述】:我有一些JSON:"foo":["bar":"baz","bar":"qux"]我想将其反序列化为一个集合。我已经定义了这个类:publicclassFoopublicstringbarget;set;... 查看详情

将 JSON 反序列化为对象

】将JSON反序列化为对象【英文标题】:DeserializingJSONintoanobject【发布时间】:2021-12-1621:52:42【问题描述】:我有一些JSON:"foo":["bar":"baz","bar":"qux"]我想将其反序列化为一个集合。我已经定义了这个类:publicclassFoopublicstringbarget;set;... 查看详情

如何将具有不同值的相同 JSON 对象反序列化为 java 类

】如何将具有不同值的相同JSON对象反序列化为java类【英文标题】:HowdeserializethesameJSONobjectbutwithdiferentvaluesintoajavaclass【发布时间】:2019-12-2906:40:33【问题描述】:我有以下情况:有时我会得到这个JSON对象"id":1,"cp":"male","money":10.... 查看详情

JSON将Scala案例类序列化为仅字符串和整数

...和整数。意思是,如果有嵌套类型,它会被序列化为JSON对象的字符串化版本,而不是JSON对象。例子:caseclassDeepest(someNum:Int)caseclassIn 查看详情

如何将具有嵌套属性的 JSON 对象反序列化为 Symfony 实体?

】如何将具有嵌套属性的JSON对象反序列化为Symfony实体?【英文标题】:HowdoIdeserializeaJSONobject-whichhasanestedproperty-toaSymfonyentity?【发布时间】:2021-09-2123:14:45【问题描述】:我正在将JSON反序列化为一个php类(一个Symfony实体),它... 查看详情

将 JSON 反序列化为现有对象 (Java)

】将JSON反序列化为现有对象(Java)【英文标题】:DeserializeJSONintoexistingobject(Java)【发布时间】:2012-09-1304:09:20【问题描述】:我想知道如何让JacksonJSON库将JSON反序列化为现有对象?我试图找到如何做到这一点;但它似乎只能接受... 查看详情

无法使用 Jackson ObjectMapper 将 Json 序列化为 Java 对象

】无法使用JacksonObjectMapper将Json序列化为Java对象【英文标题】:Can\'tserializeJsontoJavaobjectusingJacksonObjectMapper【发布时间】:2019-08-2123:12:30【问题描述】:我正在编写一个可以导出/导入数据的Javaspringbootmvc应用程序。我写了一个包... 查看详情

使用 Jackson 将通用 java 对象序列化为 JSON

】使用Jackson将通用java对象序列化为JSON【英文标题】:SerializinggenericjavaobjecttoJSONusingJackson【发布时间】:2011-12-2317:37:50【问题描述】:当我尝试将以下类实例转换为JSON(使用Jackson)时publicclassRPCRespond<Result>privateintcode;private... 查看详情

Newton JSON 如何将对象序列化为空括号?

】NewtonJSON如何将对象序列化为空括号?【英文标题】:NewtonJSONHowtoserializeobjecttoemptybrackets?【发布时间】:2021-11-1622:03:42【问题描述】:我有一个通用的对象类publicclassMyClass[Required]publicstringTitleget;set;[Required]publicintOrderIndexget;set;... 查看详情

将json字符串反序列化为python中的对象

】将json字符串反序列化为python中的对象【英文标题】:Deserializeajsonstringtoanobjectinpython【发布时间】:2013-03-0619:10:21【问题描述】:我有以下字符串"action":"print","method":"onData","data":"MadanMohan"我想反序列化为类的对象classpayloadstringa... 查看详情

无法将 JSON 数组反序列化为 C# 对象 [关闭]

】无法将JSON数组反序列化为C#对象[关闭]【英文标题】:UnableDeserializeJSONArraytoC#object[closed]【发布时间】:2021-09-2812:24:24【问题描述】:我有一个HTML页面和一些进行AJAX调用的Javascript代码。在我的API(C#)的服务器端,我收到一个JSON... 查看详情

Python将类序列化为JSON [重复]

...:2017-01-2014:34:32【问题描述】:我有一个要构建大量JSON对象的需求。并且有许多不同的定义,理想情况下我想像类一样管理它们并构造对象并按需将它们转储到JSON。是否有现成的包装/食谱让我可以执行以下操作为了简单起见,... 查看详情

将Json字符串反序列化为对象java

】将Json字符串反序列化为对象java【英文标题】:DeserializeJsonstringtoobjectjava【发布时间】:2020-02-0312:15:20【问题描述】:我得到了正确的字符串形式的响应。但是当我尝试将它建模到我的模型类时,我无法获得这些值。我猜我没... 查看详情

将objective-c自定义对象序列化为OSX的JSON?

】将objective-c自定义对象序列化为OSX的JSON?【英文标题】:serializeobjective-ccustomobjecttoJSONforOSX?【发布时间】:2012-10-0921:37:33【问题描述】:我是Mac开发的新手,在寻找好的资源时遇到了一些麻烦。我当前的问题是自定义objective-c... 查看详情

Symfony SerializerInterface 将 json 反序列化为类不起作用

...来很容易,但由于某种原因不能按预期工作。属性之一是对象数组,当反序 查看详情

轻松将对象序列化为 JSON

】轻松将对象序列化为JSON【英文标题】:EasilyserializeanobjecttoJSON【发布时间】:2015-01-1913:31:12【问题描述】:如何将Swift对象序列化为JSON,例如以下对象:classOrdervarid:Intvartitle:Stringvaremail:Stringinit(id:Int,title:String,email:String)self.id=i... 查看详情