7

シナリオ

この回答を読んだ後、JSON リテラルからオブジェクトを作成できることに気付きました。

したがって、この便利な JSON メソッドを使用するだけで、反対のことができると思いました: JSON.stringify(myObject).

だから私は次のようにしました:

function MyObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = function()
  {
    return JSON.stringify(this);
  }

}

しかし、このようなもの ( demo ) を実行すると、Maximum call stack size exceededエラーが発生します。

少しグーグルで調べたところ、この動作を説明する2つの参考文献が見つかりました。

私が正しければ.toJSON.stringify. したがって、最初のものが 2 番目のものを呼び出すと、ループが生成されます。

質問

  1. (全般) なぜこのデザインを選択したのですか? toJSONは特別なキーワードの一種の予約ですか?
  2. .toJSON(特定)名前を に変更して、stackoverflow のバグを解決しまし.displayた。それほどエレガントではありません。別の解決策はありますか?
4

2 に答える 2

6

toJSON半予約されているためだと考えてstringifyください。オブジェクトをチェックし、呼び出されたメソッドがあるかどうかを確認し、toJSONそれを呼び出して結果を文字列化しようとします。


回避策は次のとおりです。(このコードの信頼性については不明)

var obj = {
    value: 1,
    name: "John",
    toJSON: function() {
        var ret,
            fn = this.toJSON;

        delete this.toJSON;

        ret = JSON.stringify(this);

        this.toJSON = fn;

        return ret;
    }
}

使用法:

obj.toJSON(); // "{\"value\":1,\"name\":\"John\"}"
obj.lastName = "Smith";
obj.toJSON(); // "{\"value\":1,\"name\":\"John\",\"lastName\":\"Smith\"}"

クロージャーを使用する方が少しきれいかもしれません:(そして、それは安全だと言えると思います)

var obj = {
    value: 1,
    name: "John",
    toJSON: (function() {
        function fn() {
            var ret;
            delete this.toJSON;

            ret = JSON.stringify(this);

            this.toJSON = fn;

            return ret;
        }
        return fn;
    })()
}

@filmorのコメントを読んだ後、これを処理する別の方法について考えました。それほどきれいではありませんが、機能します。

Function.callerを使用して、fnが呼び出されたかどうかを検出できますJSON.stringify

var obj = {
    value: 1,
    name: "John",
    toJSON: (function() {
        return function fn() {
            var ret;

            delete this.toJSON;

            ret = JSON.stringify(this);

            if ( fn.caller === JSON.stringify ) {
                ret = JSON.parse( ret );
            }

            this.toJSON = fn;

            return ret;
        }
    })()
}
于 2012-10-09T08:55:40.500 に答える
3

質問1、toJSON予約ですか?

予約されているかどうかはわかりませんが、たとえば、ネイティブの Date オブジェクトは toJSON を使用して文字列化された日付表現を作成します。

(new Date()).toJSON();           // -> "2012-10-20T01:58:21.427Z"
JSON.stringify({d: new Date()}); // -> {"d":"2012-10-20T01:58:21.427Z"}"

質問 2、簡単な解決策:

toJSON メソッドを無視するカスタム stringify 関数を作成します (既存の global に追加することもできますJSON)。

JSON.customStringify = function (obj) {

    var fn = obj.toJSON;
    obj.toJSON = undefined;
    var json = JSON.stringify(obj);
    obj.toJSON = fn;
    return json;
}

すべてのオブジェクトで非常に簡単に使用できるようになりました。

function MyObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = function()
  {
    return JSON.customStringify(this);
  }
}

さらに簡単にするには、次を追加します。

JSON.customStringifyMethod = function () {

    return JSON.customStringify(this);
}

オブジェクトは次のようになります。

function MyObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = JSON.customStringifyMethod;
}
于 2012-10-20T01:53:48.430 に答える