循環参照を含むJavaScriptオブジェクト定義を持っています。親オブジェクトを参照するプロパティがあります。
また、サーバーに渡されたくない関数もあります。これらのオブジェクトをどのようにシリアライズおよびデシリアライズしますか?
これを行うための最良の方法は、ダグラス・クロックフォードのstringifyを使用することだと読んだことがあります。ただし、Chromeで次のエラーが表示されます。
TypeError:循環構造をJSONに変換
コード:
function finger(xid, xparent){
this.id = xid;
this.xparent;
//other attributes
}
function arm(xid, xparent){
this.id = xid;
this.parent = xparent;
this.fingers = [];
//other attributes
this.moveArm = function() {
//moveArm function details - not included in this testcase
alert("moveArm Executed");
}
}
function person(xid, xparent, xname){
this.id = xid;
this.parent = xparent;
this.name = xname
this.arms = []
this.createArms = function () {
this.arms[this.arms.length] = new arm(this.id, this);
}
}
function group(xid, xparent){
this.id = xid;
this.parent = xparent;
this.people = [];
that = this;
this.createPerson = function () {
this.people[this.people.length] = new person(this.people.length, this, "someName");
//other commands
}
this.saveGroup = function () {
alert(JSON.stringify(that.people));
}
}
これは、この質問に対して作成したテストケースです。このコードにはエラーがありますが、基本的にはオブジェクト内にオブジェクトがあり、オブジェクトが作成されたときに親オブジェクトが何であるかを示すために各オブジェクトに参照が渡されます。各オブジェクトには、文字列化されたくない関数も含まれています。 Person.Name
などのプロパティが必要です。
サーバーに送信する前にシリアライズし、同じJSONが返されると仮定してデシリアライズするにはどうすればよいですか?
循環構造エラーは、オブジェクト自体のオブジェクトであるオブジェクトのプロパティがある場合に発生します(a -> a
)または間接的(a -> b -> a
)。
エラーメッセージを回避するには、JSON.stringifyに循環参照が発生した場合の処理を指示します。たとえば、元の人を指している(または持っていない)別の人(「親」)を指している人がいる場合、次の手順を実行します。
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
stringify
の2番目のパラメーターは、フィルター関数です。ここでは、参照されるオブジェクトをそのIDに変換するだけですが、循環参照を解除するために自由に実行できます。
次のコードを使用して上記のコードをテストできます。
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
});
ところで、多くの言語(およびDOM)で予約語であるため、「parent
」とは異なる属性名を選択します。これは、今後混乱を引き起こす傾向があります...
dojo はJSONの循環参照を次の形式で表すことができるようです:{"id":"1","me":{"$ref":"1"}}
以下に例を示します。
require(["dojox/json/ref"], function(){
var me = {
name:"Kris",
father:{name:"Bill"},
mother:{name:"Karen"}
};
me.father.wife = me.mother;
var jsonMe = dojox.json.ref.toJson(me); // serialize me
alert(jsonMe);
});
生産物:
{
"name":"Kris",
"father":{
"name":"Bill",
"wife":{
"name":"Karen"
}
},
"mother":{
"$ref":"#father.wife"
}
}
注:dojox.json.ref.fromJson
メソッドを使用して、これらの循環参照オブジェクトを逆シリアル化することもできます。
その他のリソース:
JSONで循環参照を処理するのに適したモジュールが2つ見つかりました。
これらのいずれかがニーズを満たす必要があります。
特定の状況ではリモートデバッグが不可能だったため、複雑なオブジェクトをページに記録する必要があるため、このスレッドで発生しました。 Douglas Crockford(JSONのインセプター)が所有するcycle.jsが見つかりました。これは、解析後に再接続できるように、文字列として循環参照に注釈を付けます。リサイクルされたディープコピーは、JSON.stringifyを通過しても安全です。楽しい!
https://github.com/douglascrockford/JSON-js
cycle.js:このファイルにはJSON.decycleとJSON.retrocycleの2つの関数が含まれています。これらの関数は、JSONで周期的な構造とデータをエンコードし、それらを復元することを可能にします。これは、ES5では提供されない機能です。 JSONPathは、リンクを表すために使用されます。