如何将 ES6 class 转换为 json 并将 json 解析为 javascript 中的 class 对象

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

我有一些像下面这样的 class,我使用它创建了一些对象 class。我想将此对象与所有嵌套对象一起转换为 json。并想 json 回到 class A.

的对象
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 只是在做一个浅拷贝。我想要深层复制,还想将 json 字符串转换回 class A 的对象,就像以前一样。

您可以让 class 负责自己的序列化和反序列化。然后您可以轻松地将它转换为 JSON,因为 class 应该知道它的字段以及如何转换它们。然后它应该知道如何将这个转换转回它自己的另一个实例:

注意:Stack Overflow 上的可运​​行片段会将地图记录为 {},即使它有项目。检查浏览器控制台以获得更好的视图。

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);

一般注意事项:

您必须注意只有 JSON 个可序列化的值。这包括默认值:数字、字符串、布尔值、空值、普通对象和数组。此方法为 A 和映射的实例添加 only 支持。任何其他值都可能丢失或转换。这包括函数、undefined 和 BigInts,以及任何其他自定义对象。


或者,要使对象本身与 serialisation/deserialisation 分开,您可以定义仅使用与 class 相关的数据的函数。你可以利用the replacer parameter of JSON.stringify() as well as the reviver parameter in JSON.parse()来做数据的遍历和转换。

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);

一般注意事项:

和上面一样,这只能处理可序列化的值。

此外,反序列化具有更高的风险,因为您丢失了键值对所在的上下文。仅依靠对象的属性来确定它是什么对象可能会失败。考虑这个例子,其中映射中有一个名为 "mapOfA" 的键和一个 "name"。这应该反序列化为一个地图,但因为我们只知道看到普通对象版本,而没有它 的地方,它被检测为 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

比较发生的事情的上下文:

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);


大致可以采用以下方法:

  • serialisation/deserialisation逻辑在哪里
    • class
    • 内部
    • 在 class
    • 外部
  • 对数据使用什么转换逻辑:
    • 自定义转换然后使用 JSON.stringify()/JSON.parse()
    • JSON.stringify()/JSON.parse() 带有 replacer/reviver 参数

当然有可能混合其中的一些方法。