web-dev-qa-db-de.com

Serialisierung eines ES6-Klassenobjekts als JSON

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

var myClass = new MyClass()

Ich möchte myClass zu Json serialisieren. 

Ein einfacher Weg, den ich mir vorstellen kann, ist, da jedes Mitglied tatsächlich ein Javascript-Objekt (Array usw.) ist. Ich denke, ich kann eine Variable pflegen, die die Mitgliedsvariablen enthält.

this.prop.foo = this.foo und so weiter. 

Ich habe erwartet, eine toJSON/fromJSON-Bibliothek für Klassenobjekte zu finden, da ich sie mit anderen Sprachen wie Swift/Java verwendet habe, aber keine für Javascript finden konnte. 

Vielleicht ist das Klassenkonstrukt zu neu, oder was ich frage, kann leicht ohne Bibliothek erreicht werden. 

9
eugene

Wie bei jedem anderen Objekt, das Sie in JS stringifizieren möchten, können Sie JSON.stringify verwenden:

JSON.stringify(yourObject);

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

var myClass = new MyClass()

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

Bemerkenswert ist auch, dass Sie anpassen können, wie stringify Ihr Objekt serialisiert, indem Sie ihm eine toJSON-Methode geben. Der Wert, der zur Darstellung Ihres Objekts in der resultierenden JSON-Zeichenfolge verwendet wird, ist das Ergebnis des Aufrufs der toJSON-Methode für dieses Objekt.

6
nbrooks

Ich weiß, dass diese Frage alt ist, aber ich habe meine Augen herausgekratzt, bis ich eine kompakte, "sichere" Lösung geschrieben habe. 

Bei der Deserialisierung werden Objekte zurückgegeben, denen noch Arbeitsmethoden zugeordnet sind.

Das einzige, was Sie tun müssen, ist das Registrieren der Klassen, die Sie im Konstruktor des Serializers verwenden möchten.


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

Das obige sollte ausreichen, um Sie zum Laufen zu bringen, aber mehr Details und eine reduzierte Version finden Sie hier .

4
guest

Ich bin auf diese Bibliothek gestoßen, die sowohl die Serialisierung als auch die Deserialisierung von komplexen Objekten ausführt:

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

Es gibt mindestens zwei Methoden:

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

Könnte helfen, Zeit für diejenigen zu sparen, die eine solche Lösung suchen

1
vir us

Ich habe ein Modul erstellt esserializer um dieses Problem zu lösen. Es ist ein Dienstprogramm zum Serialisieren der JavaScript-Klasseninstanz und zum Deserialisieren des "serialisierten Texts" in ein Instanzobjekt, wobei alle Klassen/Eigenschaften/Methoden usw. beibehalten werden.

Um eine Instanz zu serialisieren, rufen Sie einfach die Methode serialize() auf:

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

Der interne Mechanismus von serialize() ist: Speichern Sie die Eigenschaft der Instanz und die Informationen zu ihrem Klassennamen rekursiv in einer Zeichenfolge.

Zum Deserialisieren aus einem String rufen Sie einfach die Methode deserialize() auf und übergeben alle beteiligten Klassen als 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]);

Der interne Mechanismus von deserialize() besteht darin, das Objekt mit seinen Prototypinformationen rekursiv manuell zusammenzusetzen.

0
shaochuancs

Es ist einfach, wenn es Ihnen nichts ausmacht, die Klassendefinition in decode zu übergeben.

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

Sie müssen in der Lage sein, Objekte rekursiv neu zu initialisieren. Es ist nicht unbedingt erforderlich, einen parameterlosen Konstruktor zu haben. Sie können davonkommen, ohne einen zu haben.

So führe ich Deep Copy durch:

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

Die Idee ist einfach: Beim Serialisieren wird ein Mitglied von jedem bekannten -Typ (ein Typ, der in this.types) ist mit einem Mitglied namens typeIndex gesalbt. Nach der Deserialisierung initialisieren wir jede Unterstruktur, die eine typeIndex enthält, rekursiv und entfernen sie dann, um die Struktur nicht zu verschmutzen.

0
Dmitri Nesteruk