Tengo un gran objeto que quiero convertir a JSON y enviar. Sin embargo tiene estructura circular. Quiero tirar cualquier referencia circular que exista y enviar lo que pueda ser encadenado. ¿Cómo puedo hacer eso?
Gracias.
var obj = {
a: "foo",
b: obj
}
Quiero encadenar obj en:
{"a":"foo"}
javascript
json
node.js
Harry
fuente
fuente
Respuestas:
Usar
JSON.stringify
con un sustituto personalizado. Por ejemplo:El sustituto en este ejemplo no es 100% correcto (dependiendo de su definición de "duplicado"). En el siguiente caso, se descarta un valor:
Pero el concepto se mantiene: utilice un reemplazador personalizado y realice un seguimiento de los valores de los objetos analizados.
Como una función de utilidad escrita en es6:
fuente
Node.prototype.toJSON = function() { return 'whatever you think that is right'; };
(si desea algo más genérico / específico, simplemente intente cualquier cosa en el árbol del prototipo: HTMLDivElement implementa HTMLElement implementa Element implementa Node implementa EventTarget; nota: esto puede depender del navegador, el árbol anterior es verdadero para Chrome)var a={id:1}; JSON.stringify([a,a]);
cache
será inalcanzable developer.mozilla.org/en-US/docs/Web/JavaScript/…En Node.js, puede usar util.inspect (objeto) . Reemplaza automáticamente los enlaces circulares con "[Circular]".
Aunque está integrado (no se requiere instalación) , debe importarlo
Para usarlo, simplemente llameTambién tenga en cuenta que puede pasar el objeto de opciones para inspeccionar (vea el enlace de arriba)
Por favor, lea y felicite a los comentaristas a continuación ...
fuente
var util = require('util');
obj_str = util.inspect(thing)
, NO <s>garbage_str = JSON.stringify(util.inspect(thing))
</s>Me pregunto por qué nadie publicó la solución adecuada desde la página de MDN todavía ...
Los valores vistos deben almacenarse en un conjunto , no en una matriz (se llama al reemplazador en cada elemento ) y no hay necesidad de probar
JSON.stringify
cada elemento de la cadena que conduce a una referencia circular.Como en la respuesta aceptada, esta solución elimina todos los valores repetidos , no solo los circulares. Pero al menos no tiene una complejidad exponencial.
fuente
replacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); } return value; }; } () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); … JSON.stringify({a:1, b: '2'}, replacer)
regresaundefined
en cromosolo haz
entonces en tu archivo js
https://github.com/WebReflection/circular-json
NOTA: No tengo nada que ver con este paquete. Pero lo uso para esto.
Actualización 2020
Tenga en cuenta que CircularJSON solo está en mantenimiento y Flatted es su sucesor.
fuente
JSON
por principio.Flatted.stringify({blah: 1})
resultados[{"blah":1}]
) Veo que alguien trató de plantear un problema al respecto, y el autor los reprendió y bloqueó el tema a los comentarios.Realmente me gustó la solución de Trindaz, más detallada, sin embargo, tenía algunos errores. También los arreglé para quien quiera.
Además, agregué un límite de longitud en mis objetos de caché.
Si el objeto que estoy imprimiendo es realmente grande, quiero decir infinitamente grande, quiero limitar mi algoritmo.
fuente
La respuesta de @ RobW es correcta, ¡pero esto es más eficaz! Porque usa un hashmap / set:
fuente
{"a":{"b":{"a":"d"}}}
e incluso eliminar nodos que tienen un objeto vacío {}Tenga en cuenta que también hay un
JSON.decycle
método implementado por Douglas Crockford. Ver su ciclo.js . Esto le permite stringificar casi cualquier estructura estándar:También puede recrear objetos originales con
retrocycle
método. Por lo tanto, no tiene que eliminar ciclos de objetos para encadenarlos.Sin embargo, esto no funcionará para los nodos DOM (que son la causa típica de los ciclos en los casos de uso de la vida real). Por ejemplo, esto arrojará:
He hecho una bifurcación para resolver ese problema (vea mi bifurcación cycle.js ). Esto debería funcionar bien:
Tenga en cuenta que en mi tenedor
JSON.decycle(variable)
funciona como en el original y arrojará una excepción cuandovariable
contenga nodos / elementos DOM.Cuando lo usa
JSON.decycle(variable, true)
, acepta el hecho de que el resultado no será reversible (retrocycle no volverá a crear nodos DOM). Sin embargo, los elementos DOM deben ser identificables hasta cierto punto. Por ejemplo, si undiv
elemento tiene una identificación, se reemplazará con una cadena"div#id-of-the-element"
.fuente
JSON.decycle(a, true)
qué sucede cuando pasa true como parámetro para descifrar la función.stringifyNodes
opción sea verdadera en la bifurcación. Esto volcará por ejemplodiv
con id = "alguna-id" de la cadena:div#some-id
. Evitará algunos problemas, pero no podrá realizar un ciclo completo.Recomiendo revisar json-stringify-safe desde @ isaacs-- se usa en NPM.
Instalar:
Usar:
Esto produce:
fuente
Para futuros googlers que busquen una solución a este problema cuando no conozcan las claves de todas las referencias circulares, podrían usar un contenedor alrededor de la función JSON.stringify para descartar referencias circulares. Vea un script de ejemplo en https://gist.github.com/4653128 .
La solución esencialmente se reduce a mantener una referencia a objetos previamente impresos en una matriz y verificar eso en una función de reemplazo antes de devolver un valor. Es más restrictivo que solo descartar referencias circulares, porque también descarta imprimir un objeto dos veces, uno de los efectos secundarios es evitar las referencias circulares.
Envoltorio de ejemplo:
fuente
if(printedObjIndex)
mientras debería escribirif(printedObjIndex==false)
porqueindex
también puede ser a lo0
que se traduce afalse
menos que indique explícitamente lo contrario.===
?0 == false
estrue
,0 === false
esfalse
. ; ^) Pero preferiría no inicializarprintedObjIndex
a falso, ya que entonces puede comprobarloundefined
para que (bueno, Trindaz) no mezcle metáforas tan extrañamente.Use el método JSON.stringify con un sustituto. Lea esta documentación para más información. http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx
Encuentre una manera de llenar la matriz de reemplazo con referencias cíclicas. Puede usar el método typeof para encontrar si la propiedad es del tipo 'objeto' (referencia) y una verificación de igualdad exacta (===) para verificar la referencia circular.
fuente
var obj = {foo:obj}
no no crear una referencia circular. En su lugar, crea un objeto cuyofoo
atributo se refiere al valor anterior deobj
(undefined
si no se ha definido previamente, declarado debido avar obj
).Si
resulta en un
Entonces es posible que desee imprimir así:
fuente
evalúa a:
con la función:
fuente
Sé que esta es una vieja pregunta, pero me gustaría sugerir un paquete NPM que he creado llamado smart-circular , que funciona de manera diferente a las otras formas propuestas. Es especialmente útil si está utilizando objetos grandes y profundos .
Algunas características son:
Reemplazar referencias circulares o simplemente estructuras repetidas dentro del objeto por la ruta que conduce a su primera aparición (no solo la cadena [circular] );
Al buscar circularidades en una búsqueda de amplitud, el paquete asegura que este camino sea lo más pequeño posible, lo cual es importante cuando se trata de objetos muy grandes y profundos, donde los caminos pueden ser molestamente largos y difíciles de seguir (el reemplazo personalizado en JSON.stringify hace un DFS);
Permite reemplazos personalizados, útiles para simplificar o ignorar partes menos importantes del objeto;
Finalmente, las rutas se escriben exactamente de la manera necesaria para acceder al campo al que se hace referencia, lo que puede ayudarlo a depurar.
fuente
El segundo argumento para JSON.stringify () también permite especificar una matriz de nombres de clave que deben conservarse de cada objeto que encuentre dentro de sus datos. Esto puede no funcionar para todos los casos de uso, pero es una solución mucho más simple.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Nota: Curiosamente, la definición de objeto de OP no arroja un error de referencia circular en el último Chrome o Firefox. La definición de esta respuesta se modificó de forma que lo hizo generará un error.
fuente
Para actualizar la respuesta de anular la forma en que funciona JSON (probablemente no recomendado, pero súper simple), no lo use
circular-json
(está en desuso). En su lugar, use el sucesor, aplanado:https://www.npmjs.com/package/flatted
Tomado de la antigua respuesta anterior de @ user1541685, pero reemplazada por la nueva:
npm i --save flatted
entonces en tu archivo js
fuente
Encontré la biblioteca circular-json en github y funcionó bien para mi problema.
Algunas buenas características que encontré útiles:
fuente
Resuelvo este problema así:
fuente
_class: ClassName { data: "here" }
, así que agregué la siguiente regla.replace(/(\w+) {/g, '{ __ClassName__: "$1", ')
. En mi caso, estaba tratando de ver cómo se veía un objeto de solicitud http.Sé que esta pregunta es antigua y tiene muchas respuestas excelentes, pero publico esta respuesta debido a su nuevo sabor (es5 +)
Mostrar fragmento de código
fuente
Aunque esto se ha respondido lo suficiente, también puede eliminar explícitamente la propiedad en cuestión antes de la cadena mediante el
delete
operador.eliminar operador
Esto eliminará la necesidad de construir o mantener una lógica compleja para eliminar referencias circulares.
fuente
fuente
otra solución para resolver este problema con este tipo de objetos es usar esta biblioteca
https://github.com/ericmuyser/stringy
es simple y puedes resolverlo en unos pocos pasos.
fuente
Basado en las otras respuestas termino con el siguiente código. Funciona bastante bien con referencias circulares, objetos con constructores personalizados.
Del objeto dado a ser serializado,
Enlace Github - DecycledJSON
Ejemplo de uso 1:
Ejemplo de uso 2:
fuente
Prueba esto:
fuente
seen.push(value)
= -D? Me gustafor (var key in value) {value[key] = circular_replacer(value[key]);}
En mi solución, si te encuentras con un ciclo, no solo dice "ciclo" (o nada), dice algo como foo: mira el objeto # 42 arriba, y para ver dónde apunta foo puedes desplazarte hacia arriba y buscar para el objeto # 42 (cada objeto, cuando comienza, dice el objeto # xxx con algún entero xxx)
Retazo:
fuente