2012-02-21 15 views
111

Tengo un objeto (árbol de análisis sintáctico) que contiene nodos secundarios que son referencias a otros nodos.Objeto de serialización que contiene el valor de objeto cíclico

Me gustaría serializar este objeto, usando JSON.stringify(), pero obtengo: TypeError: cyclic object value debido a los constructos que mencioné.

¿Cómo podría solucionar esto? No me importa si estas referencias a otros nodos están representadas o no en el objeto serializado.

Por otro lado, quitar estas propiedades del objeto cuando se están creando parece tedioso y no me gustaría hacer cambios en el analizador (narciso).

+1

No podemos ayudarlo sin algún código. Por favor, publique los bits relevantes de su objeto y/o salida JSON junto con el JS que usa para serializarlo. – Bojangles

+1

¿puede agregar algún prefijo a las propiedades que son referencias internas? – wheresrhys

+0

@Loic Sería valioso tener 'cycle.js' de Douglas Crockford como una respuesta aquí, ya que es la solución más adecuada para muchos casos. Parece apropiado que publiques esa respuesta, ya que eres el primero en hacer referencia a ella (en tu comentario a continuación). Si no tiene ganas de publicarlo como una respuesta, eventualmente lo haré. –

Respuesta

157

usar el segundo parámetro de stringify, la replacer function, para excluir objetos ya serializados:

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/

Como señaló correctamente en otros comentarios, el código elimina todos los objetos "visto", no solo "recursivos".

Por ejemplo, para:

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

el resultado será incorrecto. Si su estructura es así, Crockford's decycle es una mejor opción.

+2

aaah agradable! Gracias, voy a intentar esto. Encontré una solución creada por Douglas Crockford (https://github.com/douglascrockford/JSON-js/blob/master/cycle.js), pero como no estoy seguro de la licencia que la acompaña, la solución fácil que describes ¡seria perfecto! –

+3

@LoicDuros La licencia es de "dominio público". Es decir, puedes hacer lo que quieras con él. –

+1

este código produce ciclos de ciclismo, ten cuidado con el uso, muy potencial bloquea tu aplicación. necesita puntos y comas correctos y no se puede usar en objetos de evento! –

1

mucho ahorro y muestra dónde estaba el objeto del ciclo.

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

produce

jsonify = {"g":{"d":[2,5],"j":2},"e":10,"someloopshere":[{"d":[2,5],"j":2},"__cycle__",{"a":[10,"__cycle__"]}]} 
+0

, pero todavía hay un problema con este código si alguien construye un objeto con 'obj.b = this'' if alguien sabe cómo evitar cálculos muy largos hechos de un alcance erróneo dado con 'this' sería bueno ver aquí –

+2

Esto debería ser' seen.indexOf (v)! = -1' –

2

He creado un Gist GitHub que es capaz de detectar estructuras cíclicas y también de- y los codifica: https://gist.github.com/Hoff97/9842228

Para transformar sólo tiene que utilizar JSONE.stringify/JSONE.parse. También descodifica y codifica funciones. Si desea deshabilitar esto simplemente elimine las líneas 32-48 y 61-85.

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

puede encontrar un ejemplo violín aquí:

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

+1

Agradable, pero no está manejando Fecha .. – Seraph

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

Una condición previa faltaba, de lo contrario los valores enteros en objetos de matriz son truncada, es decir, [[11/08/2014 12: 30:13, 1095]] 1095 se reduce a 095.

0

Creo también un proyecto github que puede serializar un objeto cíclico y restaurar la clase si lo guarda en serialización nombre del atributo como una cadena

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

Editar: tengo transformar mi guión para la NGP https://github.com/bormat/borto_circular_serialize y tengo los nombres de función de cambio del francés al Inglés.

+0

Este ejemplo no se ajusta al Gist. El Gist tiene errores. –

+0

Buena idea, pero una vez que esté lista :-) Si la distribuyes en npm, tal vez desarrolles incluso tipings para eso, probablemente sea bastante popular. – peterh

+0

sí, buena idea. – bormat

Cuestiones relacionadas