web-dev-qa-db-fra.com

Sérialisation d'un objet contenant une valeur d'objet cyclique

J'ai un objet (arbre d'analyse) qui contient des nœuds enfants qui sont des références à d'autres nœuds.

J'aimerais sérialiser cet objet en utilisant JSON.stringify(), mais j'obtiens: TypeError: cyclic object value à cause des constructions que j'ai mentionnées.

Comment pourrais-je contourner cela? Peu m'importe que ces références à d'autres nœuds soient représentées ou non dans l'objet sérialisé.

D'autre part, supprimer ces propriétés de l'objet lors de leur création semble fastidieux et je ne voudrais pas apporter de modifications à l'analyseur (narcisse).

139
Loic Duros

Utilisez le deuxième paramètre de stringify, le fonction de remplacement , pour exclure les objets déjà sérialisés:

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/

Comme indiqué à juste titre dans d'autres commentaires, ce code supprime tous les objets "vus", pas seulement les "récursifs".

Par exemple, pour:

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

le résultat sera incorrect. Si votre structure ressemble à ceci, vous pouvez utiliser la fonction decycle de Crockford ou cette fonction (plus simple) qui remplace simplement les références récursives par des valeurs NULL:

function decycle(obj, stack = []) {
    if (!obj || typeof obj !== 'object')
        return obj;
    
    if (stack.includes(obj))
        return null;

    let s = stack.concat([obj]);

    return Array.isArray(obj)
        ? obj.map(x => decycle(x, s))
        : Object.fromEntries(
            Object.entries(obj)
                .map(([k, v]) => [k, decycle(v, s)]));
}

//

let a = {b: [1, 2, 3]}
a.b.Push(a);

console.log(JSON.stringify(decycle(a)))
201
georg

J'ai créé un Gist GitHub capable de détecter les structures cycliques et également de les coder et les coder: https://Gist.github.com/Hoff97/9842228

Pour transformer, utilisez simplement JSONE.stringify/JSONE.parse. De plus, il code et décode les fonctions. Si vous souhaitez le désactiver, supprimez simplement les lignes 32 à 48 et 61 à 85.

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

Vous pouvez trouver un exemple de violon ici:

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

2
Hoff

beaucoup d'économiseur et il montre où un cycle objet était.

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

produit

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

Une condition préalable était manquante, sinon les valeurs entières dans les objets de tableau sont tronquées, c'est-à-dire que [[[08.11.2014 12:30:13, 1095]] 1095 est réduit à 095.

1
user3893329

Je crée aussi un projet github capable de sérialiser un objet cyclique et de restaurer la classe si vous la sauvegardez dans l'attribut serializename comme une chaîne.

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

Edit: J'ai transformé mon script pour NPM https://github.com/bormat/borto_circular_serialize et j'ai changé le nom des fonctions du français à l'anglais.

1
bormat