Serializing an ES6 class object as JSON

2020-03-10 04:42发布

class MyClass {
  constructor() {
    this.foo = 3
  }
}

var myClass = new MyClass()

I'd like to serialize myClass object to json.

One easy way I can think of is, since every member is actually javascript object (array, etc..) I guess I can maintain a variable to hold the member variables.

this.prop.foo = this.foo and so on.

I expected to find a toJSON/fromJSON library for class objects since I used them with other languages such as swift/java, but couldn't find one for javascript.

Maybe class construct is too new, or what I'm asking can be somehow easily achieved without a library.

6条回答
Rolldiameter
2楼-- · 2020-03-10 04:52

It's easy if you don't mind passing the class definition into decode.

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

查看更多
女痞
3楼-- · 2020-03-10 04:53

You need to be able to reinitialize objects recursively. Having a parameterless constructor is not essential, you can get away without having one.

Here's how I perform deep copy:

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

The idea is simple: when serializing, a member of every known type (a type that's in this.types) is anointed with a member called typeIndex. After deserialization, we recursively initialize every substructure that has a typeIndex, then get rid of it to avoid polluting the structure.

查看更多
来,给爷笑一个
4楼-- · 2020-03-10 05:04

As with any other object you want to stringify in JS, you can use JSON.stringify:

JSON.stringify(yourObject);

class MyClass {
  constructor() {
    this.foo = 3
  }
}

var myClass = new MyClass()

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

Also worth noting is that you can customize how stringify serializes your object by giving it a toJSON method. The value used to represent your object in the resulting JSON string will be the result of calling the toJSON method on that object.

查看更多
我命由我不由天
5楼-- · 2020-03-10 05:06

I've came across this library which does both serialization and deserialization of complex objects (including nested objects and arrays):

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

It has at least two methods:

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

Might help to safe time for those who are looking for such solution

查看更多
叼着烟拽天下
6楼-- · 2020-03-10 05:11

I know this question is old but I've been clawing my eyes out until I wrote a compact real, "safe", solution.

Deserialization returns objects that still have working methods attached to them.

The only thing you need to do is register the classes you want to use in the constructor of the serializer.


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

The above should be enough to get you going, but more details and minified version can be found here.

查看更多
我只想做你的唯一
7楼-- · 2020-03-10 05:11

I made a module esserializer to solve this issue. It is a utility to serialize JavaScript class instance, and deserialize the "serialized-text" into an instance object, with all Class/Property/Method etc. retained.

To serialize an instance, just invoke the serialize() method:

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

The internal mechanism of serialize() is: save the instance' property and its class name information into string, recursively.

To deserialize from string, just invoke the deserialize() method, passing all involved classes as parameter:

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

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

The internal mechanism of deserialize() is: manually compose the object with its prototype information, recursively.

查看更多
登录 后发表回答