web-dev-qa-db-ja.com

循環オブジェクト値を含むオブジェクトのシリアル化

他のノードへの参照である子ノードを含むオブジェクト(解析ツリー)があります。

JSON.stringify()を使用してこのオブジェクトをシリアライズしたいのですが、私が言った構成体のために、TypeError: cyclic object valueを取得します。

どうすればこれを回避できますか?他のノードへのこれらの参照がシリアル化されたオブジェクトで表されるかどうかは私には関係ありません。

一方、作成中のオブジェクトからこれらのプロパティを削除するのは退屈なようで、パーサー(水仙)に変更を加えたくありません。

134
Loic Duros

stringifyの2番目のパラメーターである replacer function を使用して、既にシリアル化されたオブジェクトを除外します。

var seen = [];

JSON.stringify(obj, function(key, val) {
   if (val != null && typeof val == "object") {
        if (seen.indexOf(val) >= 0) {
            return;
        }
        seen.Push(val);
    }
    return val;
});

http://jsfiddle.net/mH6cJ/38/

他のコメントで正しく指摘されているように、このコードは「再帰的」オブジェクトだけでなく、「見られた」オブジェクトをすべて削除します。

たとえば、次の場合:

a = {x:1};
obj = [a, a];

結果は不正確になります。構造がこのような場合、Crockfordの decycle がより良いオプションです。

197
georg

周期構造を検出し、それらをデコードおよびエンコードできるGitHub Gistを作成しました: https://Gist.github.com/Hoff97/9842228

変換するには、JSONE.stringify/JSONE.parseを使用するだけです。また、関数をデエンコードおよびエンコードします。これを無効にする場合は、32〜48行目と61〜85行目を削除します。

var strg = JSONE.stringify(cyclicObject);
var cycObject = JSONE.parse(strg);

ここでフィドルの例を見つけることができます:

http://jsfiddle.net/hoff97/7UYd4/

2
Hoff

ずっと節約でき、cycleオブジェクトがどこにあったかを示します。

<script>
var jsonify=function(o){
    var seen=[];
    var jso=JSON.stringify(o, function(k,v){
        if (typeof v =='object') {
            if ( !seen.indexOf(v) ) { return '__cycle__'; }
            seen.Push(v);
        } return v;
    });
    return jso;
};
var obj={
    g:{
        d:[2,5],
        j:2
    },
    e:10
};
obj.someloopshere = [
    obj.g,
    obj,
    { a: [ obj.e, obj ] }
];
console.log('jsonify=',jsonify(obj));
</script>

生産する

jsonify = {"g":{"d":[2,5],"j":2},"e":10,"someloopshere":[{"d":[2,5],"j":2},"__cycle__",{"a":[10,"__cycle__"]}]}
1
Ol Sen
function stringifyObject ( obj ) {
  if ( _.isArray( obj ) || !_.isObject( obj ) ) {
    return obj.toString()
  }
  var seen = [];
  return JSON.stringify(
    obj,
    function( key, val ) {
      if (val != null && typeof val == "object") {
        if ( seen.indexOf( val ) >= 0 )
          return
          seen.Push( val )
          }
      return val
    }
  );
}

それ以外の場合、配列オブジェクトの整数値は切り捨てられます。つまり、[[08.11.2014 12:30:13、1095]] 1095は095に減少します。

1
user3893329

繰り返しオブジェクトをシリアル化して、Stringのようなserializename属性に保存するとクラスを復元​​できるgithubプロジェクトも作成します

var d={}
var a = {b:25,c:6,enfant:d};
d.papa=a;
var b = serializeObjet(a);
assert.equal(  b, "{0:{b:25,c:6,enfant:'tab[1]'},1:{papa:'tab[0]'}}" );
var retCaseDep = parseChaine(b)
assert.equal(  retCaseDep.b, 25 );
assert.equal(  retCaseDep.enfant.papa, retCaseDep );

https://github.com/bormat/serializeStringifyParseCyclicObject

編集:NPMのスクリプトを変換しました https://github.com/bormat/borto_circular_serialize と関数名をフランス語から英語に変更しました。

0
bormat