简体   繁体   English

How to convert an ES6 class to json and parse json to that class object in javascript

[英]How to convert an ES6 class to json and parse json to that class object in javascript

I have some class like below and I created some objects using that class.我有一些 class 如下所示,我使用 class 创建了一些对象。 I want to covert this object to json with all nested objects.我想用所有嵌套对象将此 object 转换为 json。 and want back json to object of class A.并希望将 json 退回到 class A 的 object。

class A {
    constructor(n) {
        this.name = n;
        this.mapOfA = new Map();
    }
}
let a = new A("A");
let b = new A("B");
let c = new A("C");
let d = new A("D");
b.mapOfA.set("D", d);
a.mapOfA.set("B", b);
a.mapOfA.set("C", c);
let jsonString = JSON.stringify(a);
console.log(jsonString); //{"name":"A","mapOfA":{}}

JSON.stringify is just doing a shallow copy. JSON.stringify 只是做一个浅拷贝。 I want deep copy and also I want to convert back json string to object of class A like it was before.我想要深度复制,并且我想像以前一样将 json 字符串转换回 class A 的 object 。

You can make the class responsible for its own serialisation and deserialisation.您可以让 class 负责自己的序列化和反序列化。 Then you can easily convert it to JSON as the class should know its fields and how to convert them.然后您可以轻松地将其转换为 JSON 因为 class 应该知道它的字段以及如何转换它们。 Then it should know how this conversion should be turned back into another instance of itself:然后它应该知道应该如何将这个转换转换回它自己的另一个实例:

Note : the runnable snippet on Stack Overflow will log a map as {} even if it has items.注意:Stack Overflow 上的可运行代码段会将 map 记录为{} ,即使它有项目。 Check the browser console for better view.检查浏览器控制台以获得更好的视图。

 class A { constructor(n) { this.name = n; this.mapOfA = new Map(); } toObj() { //get serialisible fields const {name, mapOfA} = this; //convert complex object representation JSON serialisible format const simpleMapOfA = Object.fromEntries( //convert map to plain object Array.from( mapOfA.entries(), //transform the map ([key, value]) => [key, value.toObj()] //convert map values to plain objects ) ); //return plain object return { name, mapOfA: simpleMapOfA } } static from(obj) { //create a new instance const instance = new A(obj.name); //fill the instance `mapOfA` with the data from the input for (const [key, value] of Object.entries(obj.mapOfA)) { instance.mapOfA.set(key, A.from(value)); } return instance; } serialise() { return JSON.stringify(this.toObj()); } static deserialise(json) { return A.from(JSON.parse(json)); } } let a = new A("A"); let b = new A("B"); let c = new A("C"); let d = new A("D"); b.mapOfA.set("D", d); a.mapOfA.set("B", b); a.mapOfA.set("C", c); let jsonString = a.serialise(); console.log("serialised view:\n", jsonString); let fooA = A.deserialise(jsonString); let fooB = fooA.mapOfA.get("B"); let fooC = fooA.mapOfA.get("C"); let fooD = fooB.mapOfA.get("D"); console.log("all four objects still instances of A\n", fooA instanceof A, fooB instanceof A, fooC instanceof A, fooD instanceof A ); console.log("deserilised objects:\n", fooA, fooB, fooC, fooD);

General considerations:一般考虑:

You must take care to only have JSON serialisable values.您必须注意只有 JSON 可序列化值。 That includes the default ones: numbers, strings, booleans, nulls, plain objects, and arrays.这包括默认值:数字、字符串、布尔值、空值、普通对象和 arrays。 This approach adds support only for instances of A and maps.这种方法增加了对A和地图实例的支持。 Any other values may be lost or transformed.任何其他值都可能丢失或转换。 That includes, functions, undefined , and BigInts, as well as any other custom objects.这包括函数、 undefined和 BigInts,以及任何其他自定义对象。


Alternatively, to keep the object itself separate from the serialisation/deserialisation, you can define functions that only consume data related with your class.或者,要将 object 本身与序列化/反序列化分开,您可以定义仅使用与 class 相关的数据的函数。 You can take advantage of the replacer parameter of JSON.stringify() as well as the reviver parameter in JSON.parse() to do the traversal and conversion of the data.您可以利用JSON.stringify() 的 replacer 参数以及JSON.stringify()JSON.parse() reviver 参数对数据进行遍历和转换。

 class A { constructor(n) { this.name = n; this.mapOfA = new Map(); } } function serialiseClassA(instance) { return JSON.stringify(instance, (key, value) => { if(value instanceof A) { //only return serialisible fields const { name, mapOfA } = value; //return plain object return { name, mapOfA }; } //convert map to plain object if(value instanceof Map) { return Object.fromEntries(value); } return value; }); } function deserialiseClassA(json) { return JSON.parse(json, (key, value) => { //it is an object if (typeof value === "object" && value.== null) { //it is probably a serialised instance of A if ("name" in value && "mapOfA" in value) { //convert value to instance of A const instance = new A(value;name), //fill the instance `mapOfA` with the data from the input for (const [k. v] of value.mapOfA) { instance.mapOfA,set(k; v); } return instance. } //it is probably a serialised map if(key === "mapOfA") { //convert to a map return new Map(Object;entries(value)); } } return value; }); } let a = new A("A"); let b = new A("B"); let c = new A("C"); let d = new A("D"). b.mapOfA,set("D"; d). a.mapOfA,set("B"; b). a.mapOfA,set("C"; c); let jsonString = serialiseClassA(a). console:log("serialised view,\n"; jsonString); let fooA = deserialiseClassA(jsonString). let fooB = fooA.mapOfA;get("B"). let fooC = fooA.mapOfA;get("C"). let fooD = fooB.mapOfA;get("D"). console,log("all four objects still instances of A\n", fooA instanceof A, fooB instanceof A, fooC instanceof A; fooD instanceof A ). console:log("deserilised objects,\n", fooA, fooB, fooC; fooD);

General considerations:一般考虑:

Like the above, this can only handle values that are serialisable.和上面一样,这只能处理可序列化的值。

In addition, the deserialisation has a higher risk because you lose the context of where a key-value pair is.此外,反序列化具有更高的风险,因为您丢失了键值对所在的上下文 Relying only on the properties of an object to determine what object it was might fail.仅依靠 object 的属性来确定它是什么 object 可能会失败。 Consider this example where there is a key in the map called "mapOfA" and a "name" .考虑这个示例,其中 map 中有一个名为"mapOfA"和一个"name"的键。 That is supposed to deserialise to a map but because we only know see the plain object version, without where it was , it is detected as an instance of A and thus throws an error:这应该反序列化为 map 但因为我们只知道看到普通的 object 版本,没有它的位置,它检测为A的实例,因此引发错误:

 class A { constructor(n) { this.name = n; this.mapOfA = new Map(); } } function deserialiseClassA(json) { return JSON.parse(json, (key, value) => { //it is an object if (typeof value === "object" && value.== null) { //it is probably a serialised instance of A if ("name" in value && "mapOfA" in value) { //convert value to instance of A const instance = new A(value;name), //fill the instance `mapOfA` with the data from the input for (const [k. v] of value.mapOfA) { instance.mapOfA,set(k; v); } return instance. } //it is probably a serialised map if(key === "mapOfA") { //convert to a map return new Map(Object;entries(value)); } } return value; }): } const json = `{ "name", "A": "mapOfA": { "mapOfA": { "name", "B": "mapOfA", {} }: "name": { "name", "C": "mapOfA"; {} } } }`; deserialiseClassA(json); //error

Compare when there is context of what is happening:比较何时有正在发生的事情的上下文:

 class A { constructor(n) { this.name = n; this.mapOfA = new Map(); } static from(obj) { //create a new instance const instance = new A(obj.name); //fill the instance `mapOfA` with the data from the input for (const [key, value] of Object.entries(obj.mapOfA)) { instance.mapOfA.set(key, A.from(value)); } return instance; } static deserialise(json) { return A.from(JSON.parse(json)); } } const json = `{ "name": "A", "mapOfA": { "mapOfA": { "name": "B", "mapOfA": {} }, "name": { "name": "C", "mapOfA": {} } } }`; const fooA = A.deserialise(json); const fooB = fooA.mapOfA.get("mapOfA"); const fooC = fooA.mapOfA.get("name"); console.log("all three objects still instances of A\n", fooA instanceof A, fooB instanceof A, fooC instanceof A, ); console.log("deserilised objects:\n", fooA, fooB, fooC);


These are broadly the approaches to take:这些大致是采取的方法:

  • Where is the serialisation/deserialisation logic序列化/反序列化逻辑在哪里
    • internal to the class class 内部
    • external to the class class 外部
  • What transformation logic to use with the data:对数据使用什么转换逻辑:
    • custom transformation then using JSON.stringify() / JSON.parse()然后使用JSON.stringify() / JSON.parse()进行自定义转换
    • JSON.stringify() / JSON.parse() with a replacer/reviver parameter JSON.stringify() / JSON.parse()带有replacer/reviver参数

It of course possible an approach that mixes few of these.当然,有可能采用一种混合其中少数几种的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM