web-dev-qa-db-ja.com

ES6クラスオブジェクトをJSONとしてシリアル化する

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

var myClass = new MyClass()

myClassオブジェクトをjsonにシリアル化したいのですが。

私が考えることができる簡単な方法の1つは、すべてのメンバーが実際にはJavaScriptオブジェクト(配列など)であるためです。メンバー変数を保持する変数を維持できると思います。

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

toJSON/fromJSONクラスオブジェクトのライブラリ。Swift/ Javaなどの他の言語で使用していたため、javascript用のライブラリが見つかりませんでした。

たぶん、クラスの構成があまりにも新しいのか、私が求めていることは、ライブラリなしで何とか簡単に達成できるでしょう。

15
eugene

JSで文字列化したい他のオブジェクトと同様に、 JSON.stringify

JSON.stringify(yourObject);

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

var myClass = new MyClass()

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

また、stringifytoJSON method を指定してオブジェクトをシリアル化する方法をカスタマイズできることにも注意してください。結果のJSON文字列でオブジェクトを表すために使用される値は、そのオブジェクトでtoJSONメソッドを呼び出した結果になります。

7
nbrooks

私はこの質問が古いことを知っていますが、コンパクトで実際の「安全な」解決策を書くまで、私は目を凝らしてきました。

逆シリアル化は、作業メソッドがまだアタッチされているオブジェクトを返します。

必要なことは、シリアライザのコンストラクタで使用するクラスを登録することだけです。


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 にあります。

8
guest

複雑なオブジェクト(入れ子になったオブジェクトや配列を含む)のシリアル化と逆シリアル化の両方を行うこのライブラリに出くわしました。

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

少なくとも2つの方法があります。

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

そのような解決策を探している人のための安全な時間に役立つかもしれません

3
vir us

この問題を解決するために、モジュール 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()の内部メカニズムは、プロトタイプ情報を使用してオブジェクトを手動で再帰的に作成します。

0
shaochuancs

クラス定義をデコードに渡してもかまわない場合は簡単です。

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

オブジェクトを再帰的に再初期化できる必要があります。パラメーターなしのコンストラクターは必須ではありません。コンストラクターがなくても問題はありません。

ディープコピーを実行する方法は次のとおりです。

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

アイデアは単純です。シリアル化すると、すべてのknownタイプ(this.typesにあるタイプ)のメンバーがtypeIndexというメンバーで油注がれます。逆シリアル化の後、typeIndexを持つすべてのサブ構造を再帰的に初期化し、構造を汚染しないようにそれを削除します。

0
Dmitri Nesteruk