2012-01-08 11 views
27

JSON.stringify()を使用している場合、json2.jsは親オブジェクトのメンバーを無視しているようです。例:継承したオブジェクトをJSONに文字列化する方法は?

require('./json2.js'); 

function WorldObject(type) {  
    this.position = 4; 
} 

function Actor(val) { 
    this.someVal = 50; 
} 

Actor.prototype = new WorldObject(); 

var a = new Actor(2); 

console.log(a.position); 
console.log(JSON.stringify(a)); 

出力は次のとおりです。

4 
{"position":0, "someVal":50} 

答えて

31

まあそれがあるだけの方法だ、JSON.stringifyがnot-のいずれかを保存しない:

4 
{"someVal":50} 

私はこの出力が期待されます所有しているオブジェクトのプロパティです。他の欠点と考えられる回避策についての興味深い議論を見ることができますhere

また、著者は問題を文書化しただけでなく、HydrateJSというライブラリを作成しました。

問題は、最初の視点よりも少し深いです。 aが実際に{"position":0, "someVal":50}にストリングされたとしても、後で解析すると、目的のプロパティを持つオブジェクトが作成されますが、Actorのインスタンスでもなく、WorldObjectへのプロトタイプリンクもありません(結局のところ、この情報を持っているので、それを復元することはできません)。

プロトタイプチェーンを保存するには、HydrateJSで使用されているような巧妙なトリックが必要です。これがあなたが目指しているものでない場合は、オブジェクトを文字列化する前にオブジェクトを「平坦化」する必要があるかもしれません。これを行うには、たとえば次のようにします。オブジェクトが所有しているかどうかにかかわらず、オブジェクトのすべてのプロパティを反復し、それらを再割り当てします(プロトタイプから継承されたものではなくオブジェクト自体に確実に定義されます)。

function flatten(obj) { 
    var result = Object.create(obj); 
    for(var key in result) { 
     result[key] = result[key]; 
    } 
    return result; 
} 

元のオブジェクトを変更する方法はありません。だから、あなたが欲しいの出力を得るでしょうし、aは同じままになります

console.log(JSON.stringify(flatten(a))); 

を使用。

+0

私はこのコードは基本的に私が必要と思うものだと思います。私はこのシリアル化されたバージョンを保存し、単純なローダーを書くことができるはずです。よくやった! – wtjones

9

チェックこのフィドル:http://jsfiddle.net/AEGYG/

あなたはこの機能を使用してオブジェクトをフラット文字列化することができます

function flatStringify(x) { 
    for(var i in x) { 
     if(!x.hasOwnProperty(i)) { 
      // weird as it might seem, this actually does the trick! - adds parent property to self 
      x[i] = x[i]; 
     } 
    } 
    return JSON.stringify(x); 
} 
+0

Tomasのスニペットと同様に動作するので、私は両方の答えをマークすることができたらいいと思います。 – wtjones

20

もう一つのオプションは、シリアル化するオブジェクトのプロトタイプでtoJSON方法を定義するには、次のようになります。

function Test(){} 

Test.prototype = { 

    someProperty: "some value", 

    toJSON: function() { 
     var tmp = {}; 

     for(var key in this) { 
      if(typeof this[key] !== 'function') 
       tmp[key] = this[key]; 
     } 

     return tmp; 
    } 
}; 

var t = new Test; 

JSON.stringify(t); // returns "{"someProperty" : "some value"}" 

これはJSON.stringifyが受け取ったオブジェクトのtoJSONメソッドを検索してからシリアライズ。

1

flattenのアプローチは一般的には機能しますが、これまでに投稿されたその他の回答のスニペットは、プロトタイプがfrozenの場合など、変更できないプロパティでは機能しません。このケースを処理するには、新しいオブジェクトを作成し、この新しいオブジェクトにプロパティを割り当てる必要があります。結果として得られるオブジェクトをストリング化するだけなので、オブジェクトのアイデンティティやその他のJavaScriptの内部構造はおそらく問題ではないので、新しいオブジェクトを返すのはまったく問題ありません。それはノーオペレーションのようには見えませんので、このアプローチは、また、それ自体に、オブジェクトのプロパティを再割り当てするよりも間違いなく、より読みやすいです:ここでは

function flatten(obj) { 
    var ret = {}; 
    for (var i in obj) { 
     ret[i] = obj[i]; 
    } 
    return ret; 
} 
1

はで、彼の答えに含まスニペット@TomasVanaの再帰バージョンです場合が継承は、オブジェクトツリーの複数のレベルにあります。

var flatten = function(obj) { 
    if (obj === null) { 
     return null; 
    } 

    if (Array.isArray(obj)) { 
     var newObj = []; 
     for (var i = 0; i < obj.length; i++) { 
      if (typeof obj[i] === 'object') { 
       newObj.push(flatten(obj[i])); 
      } 
      else { 
       newObj.push(obj[i]); 
      } 
     } 
     return newObj; 
    } 

    var result = Object.create(obj); 
    for(var key in result) { 
     if (typeof result[key] === 'object') { 
      result[key] = flatten(result[key]); 
     } 
     else { 
      result[key] = result[key]; 
     } 
    } 
    return result; 
} 

そしてそれは、配列として配列を保持します。

console.log(JSON.stringify(flatten(visualDataViews))); 
関連する問題