parse objeto examples diferencia convertir array and javascript json node.js

objeto - json.stringify javascript



JSON.stringify, evita TypeError: Convertir estructura circular a JSON (19)

Tengo un objeto grande que quiero convertir a JSON y enviar. Sin embargo, tiene estructura circular. Quiero tirar cualquier referencia circular que exista y enviar cualquier cosa que pueda ser tildada. ¿Cómo puedo hacer eso?

Gracias.

var obj = { a: "foo", b: obj }

Quiero encadenar obj en:

{"a":"foo"}


Basándome en las otras respuestas termino con el siguiente código. Funciona bastante bien con referencias circulares, objetos con constructores personalizados.

Del objeto dado para ser serializado,

  • Almacene en caché todo el objeto con el que se encuentre mientras atraviesa el objeto y asigne a cada uno un hashID único (también funciona un número de incremento automático)
  • Una vez que se encuentra una referencia circular, marque ese campo en el nuevo objeto como circular y almacene el hashID del objeto original como un atributo.

Enlace Github - DecycledJSON

DJSHelper = {}; DJSHelper.Cache = []; DJSHelper.currentHashID = 0; DJSHelper.ReviveCache = []; // DOES NOT SERIALIZE FUNCTION function DJSNode(name, object, isRoot){ this.name = name; // [ATTRIBUTES] contains the primitive fields of the Node this.attributes = {}; // [CHILDREN] contains the Object/Typed fields of the Node // All [CHILDREN] must be of type [DJSNode] this.children = []; //Array of DJSNodes only // If [IS-ROOT] is true reset the Cache and currentHashId // before encoding isRoot = typeof isRoot === ''undefined''? true:isRoot; this.isRoot = isRoot; if(isRoot){ DJSHelper.Cache = []; DJSHelper.currentHashID = 0; // CACHE THE ROOT object.hashID = DJSHelper.currentHashID++; DJSHelper.Cache.push(object); } for(var a in object){ if(object.hasOwnProperty(a)){ var val = object[a]; if (typeof val === ''object'') { // IF OBJECT OR NULL REF. /***************************************************************************/ // DO NOT REMOVE THE [FALSE] AS THAT WOULD RESET THE [DJSHELPER.CACHE] // AND THE RESULT WOULD BE /***************************************************************************/ if(val !== null) { if (DJSHelper.Cache.indexOf(val) === -1) { // VAL NOT IN CACHE // ADD THE VAL TO CACHE FIRST -> BEFORE DOING RECURSION val.hashID = DJSHelper.currentHashID++; //console.log("Assigned", val.hashID, "to", a); DJSHelper.Cache.push(val); if (!(val instanceof Array)) { // VAL NOT AN [ARRAY] try { this.children.push(new DJSNode(a, val, false)); } catch (err) { console.log(err.message, a); throw err; } } else { // VAL IS AN [ARRAY] var node = new DJSNode(a, { array: true, hashID: val.hashID // HashID of array }, false); val.forEach(function (elem, index) { node.children.push(new DJSNode("elem", {val: elem}, false)); }); this.children.push(node); } } else { // VAL IN CACHE // ADD A CYCLIC NODE WITH HASH-ID this.children.push(new DJSNode(a, { cyclic: true, hashID: val.hashID }, false)); } }else{ // PUT NULL AS AN ATTRIBUTE this.attributes[a] = ''null''; } } else if (typeof val !== ''function'') { // MUST BE A PRIMITIVE // ADD IT AS AN ATTRIBUTE this.attributes[a] = val; } } } if(isRoot){ DJSHelper.Cache = null; } this.constructorName = object.constructor.name; } DJSNode.Revive = function (xmlNode, isRoot) { // Default value of [isRoot] is True isRoot = typeof isRoot === ''undefined''?true: isRoot; var root; if(isRoot){ DJSHelper.ReviveCache = []; //Garbage Collect } if(window[xmlNode.constructorName].toString().indexOf(''[native code]'') > -1 ) { // yep, native in the browser if(xmlNode.constructorName == ''Object''){ root = {}; }else{ return null; } }else { eval(''root = new '' + xmlNode.constructorName + "()"); } //CACHE ROOT INTO REVIVE-CACHE DJSHelper.ReviveCache[xmlNode.attributes.hashID] = root; for(var k in xmlNode.attributes){ // PRIMITIVE OR NULL REF FIELDS if(xmlNode.attributes.hasOwnProperty(k)) { var a = xmlNode.attributes[k]; if(a == ''null''){ root[k] = null; }else { root[k] = a; } } } xmlNode.children.forEach(function (value) { // Each children is an [DJSNode] // [Array]s are stored as [DJSNode] with an positive Array attribute // So is value if(value.attributes.array){ // ITS AN [ARRAY] root[value.name] = []; value.children.forEach(function (elem) { root[value.name].push(elem.attributes.val); }); //console.log("Caching", value.attributes.hashID); DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name]; }else if(!value.attributes.cyclic){ // ITS AN [OBJECT] root[value.name] = DJSNode.Revive(value, false); //console.log("Caching", value.attributes.hashID); DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name]; } }); // [SEPARATE ITERATION] TO MAKE SURE ALL POSSIBLE // [CYCLIC] REFERENCES ARE CACHED PROPERLY xmlNode.children.forEach(function (value) { // Each children is an [DJSNode] // [Array]s are stored as [DJSNode] with an positive Array attribute // So is value if(value.attributes.cyclic){ // ITS AND [CYCLIC] REFERENCE root[value.name] = DJSHelper.ReviveCache[value.attributes.hashID]; } }); if(isRoot){ DJSHelper.ReviveCache = null; //Garbage Collect } return root; }; DecycledJSON = {}; DecycledJSON.stringify = function (obj) { return JSON.stringify(new DJSNode("root", obj)); }; DecycledJSON.parse = function (json, replacerObject) { // use the replacerObject to get the null values return DJSNode.Revive(JSON.parse(json)); }; DJS = DecycledJSON;

Ejemplo de uso 1:

var obj = { id:201, box: { owner: null, key: ''storm'' }, lines:[ ''item1'', 23 ] }; console.log(obj); // ORIGINAL // SERIALIZE AND THEN PARSE var jsonObj = DJS.stringify(obj); console.log(DJS.parse(jsonObj));

Ejemplo de uso 2:

// PERSON OBJECT function Person() { this.name = null; this.child = null; this.dad = null; this.mom = null; } var Dad = new Person(); Dad.name = ''John''; var Mom = new Person(); Mom.name = ''Sarah''; var Child = new Person(); Child.name = ''Kiddo''; Dad.child = Mom.child = Child; Child.dad = Dad; Child.mom = Mom; console.log(Child); // ORIGINAL // SERIALIZE AND THEN PARSE var jsonChild = DJS.stringify(Child); console.log(DJS.parse(jsonChild));


El segundo argumento de JSON.stringify () también le permite especificar una matriz de nombres de claves 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

var obj = { a: "foo", b: this } var json = JSON.stringify(obj, [''a'']); console.log(json); // {"a":"foo"}

Nota: Extrañamente, la definición de objeto de OP no produce un error de referencia circular en el último Chrome o Firefox. La definición en esta respuesta fue modificada para que arrojara un error.


En Node.js, puede usar util.inspect(object) . Reemplaza automáticamente los enlaces circulares con "[Circular]".

Si bien está integrado (no se requiere instalación) , debe importarlo

import * as util from ''util'' // has no default export import { inspect } from ''util'' // or directly // or var util = require(''util'') Para usarlo, simplemente llame

console.log(util.inspect(myObject))

También tenga en cuenta que puede pasar el objeto de opciones para inspeccionar (vea el enlace arriba)

inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])


Por favor, lea y felicite a los comentaristas a continuación ...


Encontré la https://github.com/WebReflection/circular-json y funcionó bien para mi problema.

Algunas buenas características que me parecieron útiles:

  • Admite el uso multiplataforma, pero solo lo he probado con node.js hasta ahora.
  • La API es la misma, por lo que todo lo que necesita hacer es incluirla y usarla como un reemplazo JSON.
  • Tiene su propio método de análisis para que pueda convertir los datos serializados ''circulares'' de nuevo a objeto.

La respuesta de @ RobW es correcta, ¡pero esto es más eficaz! Porque usa un hashmap / set:

const customStringify = function (v) { const cache = new Set(); return JSON.stringify(v, function (key, value) { if (typeof value === ''object'' && value !== null) { if (cache.has(value)) { // Circular reference found, discard key return; } // Store value in our set cache.add(value); } return value; }); };


Otra solución para resolver este problema con este tipo de objetos es el uso de esta biblioteca.

https://github.com/ericmuyser/stringy

Es simple y puedes resolverlo en unos pocos pasos.


Para los futuros googlers que buscan una solución a este problema cuando no conoce las claves de todas las referencias circulares, puede usar un envoltorio 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 básicamente 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 la impresión de un objeto dos veces, uno de los efectos secundarios es evitar las referencias circulares.

Ejemplo de envoltura:

function stringifyOnce(obj, replacer, indent){ var printedObjects = []; var printedObjectKeys = []; function printOnceReplacer(key, value){ var printedObjIndex = false; printedObjects.forEach(function(obj, index){ if(obj===value){ printedObjIndex = index; } }); if(printedObjIndex && typeof(value)=="object"){ return "(see " + value.constructor.name.toLowerCase() + " with key " + printedObjectKeys[printedObjIndex] + ")"; }else{ var qualifiedKey = key || "(empty key)"; printedObjects.push(value); printedObjectKeys.push(qualifiedKey); if(replacer){ return replacer(key, value); }else{ return value; } } } return JSON.stringify(obj, printOnceReplacer, indent); }


Prueba esto:

var obj = { a: "foo", b: obj }; var circular_replacer = (value) => { var seen = []; if (value != null && typeof value == "object") { if (seen.indexOf(value) >= 0) return; seen.push(value); } return value; }; obj = circular_replacer(obj);


Realmente me gustó la solución de Trindaz, más detallada, sin embargo, tenía algunos errores. Los arreglé para que a quien le guste también.

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.

JSON.stringifyOnce = function(obj, replacer, indent){ var printedObjects = []; var printedObjectKeys = []; function printOnceReplacer(key, value){ if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don''t see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects return ''object too long''; } var printedObjIndex = false; printedObjects.forEach(function(obj, index){ if(obj===value){ printedObjIndex = index; } }); if ( key == ''''){ //root element printedObjects.push(obj); printedObjectKeys.push("root"); return value; } else if(printedObjIndex+"" != "false" && typeof(value)=="object"){ if ( printedObjectKeys[printedObjIndex] == "root"){ return "(pointer to root)"; }else{ return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")"; } }else{ var qualifiedKey = key || "(empty key)"; printedObjects.push(value); printedObjectKeys.push(qualifiedKey); if(replacer){ return replacer(key, value); }else{ return value; } } } return JSON.stringify(obj, printOnceReplacer, indent); };


Recomiendo revisar json-stringify-safe de @ isaacs-- se usa en NPM.

Por cierto, si no estás usando Node.js, puedes copiar y pegar las líneas 4-27 de la parte relevante del código fuente .

Instalar:

$ npm install json-stringify-safe --save

Usar:

// Require the thing var stringify = require(''json-stringify-safe''); // Take some nasty circular object var theBigNasty = { a: "foo", b: theBigNasty }; // Then clean it up a little bit var sanitized = JSON.parse(stringify(theBigNasty));

Esto produce:

{ a: ''foo'', b: ''[Circular]'' }

Tenga en cuenta que, al igual que con la función vanilla JSON.stringify como se menciona en @Rob W, también puede personalizar el comportamiento de desinfección pasando una función de "reemplazo" como segundo argumento para stringify() . Si necesita un ejemplo sencillo de cómo hacerlo, acabo de escribir un sustituto personalizado que obliga a errores, expresiones regulares y funciones en cadenas legibles por humanos here .


Resuelvo este problema así:

var util = require(''util''); // Our circular object var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: ''Yo!''}}}}}}}}; obj.foo.bar = obj; // Generate almost valid JS object definition code (typeof string) var str = util.inspect(b, {depth: null}); // Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case) str = str .replace(/<Buffer[ /w/.]+>/ig, ''"buffer"'') .replace(//[Function]/ig, ''function(){}'') .replace(//[Circular]/ig, ''"Circular"'') .replace(//{ /[Function: ([/w]+)]/ig, ''{ $1: function $1 () {},'') .replace(//[Function: ([/w]+)]/ig, ''function $1(){}'') .replace(/(/w+): ([/w :]+GMT/+[/w /(/)]+),/ig, ''$1: new Date("$2"),'') .replace(/(/S+): ,/ig, ''$1: null,''); // Create function to eval stringifyed code var foo = new Function(''return '' + str + '';''); // And have fun console.log(JSON.stringify(foo(), null, 4));


Sé que esta es una pregunta antigua, 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:

  • Reemplazo de referencias circulares o simplemente estructuras repetidas dentro del objeto por el camino que conduce a su primera aparición (no solo la cadena [circular] );

  • Al buscar circularidades en una búsqueda de amplitud, el paquete garantiza 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 molestos 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 realizar la depuración.


Sé que esta pregunta es antigua y tiene muchas respuestas geniales, pero publico esta respuesta debido a su nuevo sabor (es5 +)

Object.defineProperties(JSON, { refStringify: { value: function(obj) { let objMap = new Map(); let stringified = JSON.stringify(obj, function(key, value) { // only for objects if (typeof value == ''object'') { // If has the value then return a reference to it if (objMap.has(value)) return objMap.get(value); objMap.set(value, `ref${objMap.size + 1}`); } return value; }); return stringified; } }, refParse: { value: function(str) { let parsed = JSON.parse(str); let objMap = _createObjectMap(parsed); objMap.forEach((value, key) => _replaceKeyWithObject(value, key)); return parsed; } }, }); // *************************** Example let a = { b: 32, c: { get a() { return a; }, get c() { return a.c; } } }; let stringified = JSON.refStringify(a); let parsed = JSON.refParse(stringified, 2); console.log(parsed, JSON.refStringify(parsed)); // *************************** /Example // *************************** Helper function _createObjectMap(obj) { let objMap = new Map(); JSON.stringify(obj, (key, value) => { if (typeof value == ''object'') { if (objMap.has(value)) return objMap.get(value); objMap.set(value, `ref${objMap.size + 1}`); } return value; }); return objMap; } function _replaceKeyWithObject(key, obj, replaceWithObject = obj) { Object.keys(obj).forEach(k => { let val = obj[k]; if (val == key) return (obj[k] = replaceWithObject); if (typeof val == ''object'' && val != replaceWithObject) _replaceKeyWithObject(key, val, replaceWithObject); }); }


Si

console.log(JSON.stringify(object));

resultados en un

TypeError: valor de objeto cíclico

Entonces es posible que desee imprimir así:

var output = ''''; for (property in object) { output += property + '': '' + object[property]+''; ''; } console.log(output);


Tenga en cuenta que también hay un método JSON.decycle implementado por Douglas Crockford. Ver su cycle.js . Esto le permite alinear casi cualquier estructura estándar:

var a = []; a[0] = a; a[1] = 123; console.log(JSON.stringify(JSON.decycle(a))); // result: ''[{"$ref":"$"},123]''.

También puede recrear el objeto original con el método de retrocycle . Por lo tanto, no es necesario eliminar los ciclos de los objetos para alinearlos.

Sin embargo, esto no funcionará para los Nodos DOM (que son la causa típica de los ciclos en casos de uso de la vida real). Por ejemplo esto lanzará:

var a = [document.body]; console.log(JSON.stringify(JSON.decycle(a)));

He hecho un tenedor para resolver ese problema (ver mi tenedor de cycle.js ). Esto debería funcionar bien:

var a = [document.body]; console.log(JSON.stringify(JSON.decycle(a, true)));

Tenga en cuenta que en mi bifurcación JSON.decycle(variable) funciona como en el original y lanzará una excepción cuando la variable contenga nodos / elementos DOM.

Cuando utiliza JSON.decycle(variable, true) , acepta el hecho de que el resultado no será reversible (el retrociclo no volverá a crear los nodos DOM). Sin embargo, los elementos DOM deben ser identificables en cierta medida. Por ejemplo, si un elemento div tiene un id, se reemplazará con una cadena "div#id-of-the-element" .


Utilice JSON.stringify con un sustituto personalizado. Por ejemplo:

// Demo: Circular reference var o = {}; o.o = o; // Note: cache should not be re-used by repeated calls to JSON.stringify. var cache = []; JSON.stringify(o, function(key, value) { if (typeof value === ''object'' && value !== null) { if (cache.indexOf(value) !== -1) { // Duplicate reference found try { // If this value does not reference a parent it can be deduped return JSON.parse(JSON.stringify(value)); } catch (error) { // discard key if value cannot be deduped return; } } // Store value in our collection cache.push(value); } return value; }); cache = null; // Enable garbage collection

El sustituto en este ejemplo no es 100% correcto (dependiendo de su definición de "duplicado"). En el siguiente caso, se desecha un valor:

var a = {b:1} var o = {}; o.one = a; o.two = a; // one and two point to the same object, but two is discarded: JSON.stringify(o, ...);

Pero el concepto es válido: utilice un sustituto personalizado y realice un seguimiento de los valores de los objetos analizados.


Utilice 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

var obj = { a: "foo", b: obj } var replacement = {"b":undefined}; alert(JSON.stringify(obj,replacement));

Descubra una manera de rellenar la matriz de reemplazo con referencias cíclicas. Puede usar el método typeof para encontrar si una propiedad es de tipo ''objeto'' (referencia) y una verificación de igualdad exacta (===) para verificar la referencia circular.


solo haz

npm i --save circular-json

entonces en tu archivo js

const JSON = require(''circular-json''); ... const json = JSON.stringify(obj);

Tambien podrias hacer

const CircularJSON = require(''circular-json'');

https://github.com/WebReflection/circular-json

NOTA: No tengo nada que ver con este paquete. Pero sí lo uso para esto.


var a={b:"b"}; a.a=a; JSON.stringify(preventCircularJson(a));

evalúa a:

"{"b":"b","a":"CIRCULAR_REFERENCE_REMOVED"}"

con la función:

/** * Traverses a javascript object, and deletes all circular values * @param source object to remove circular references from * @param censoredMessage optional: what to put instead of censored values * @param censorTheseItems should be kept null, used in recursion * @returns {undefined} */ function preventCircularJson(source, censoredMessage, censorTheseItems) { //init recursive value if this is the first call censorTheseItems = censorTheseItems || [source]; //default if none is specified censoredMessage = censoredMessage || "CIRCULAR_REFERENCE_REMOVED"; //values that have allready apeared will be placed here: var recursiveItems = {}; //initaite a censored clone to return back var ret = {}; //traverse the object: for (var key in source) { var value = source[key] if (typeof value == "object") { //re-examine all complex children again later: recursiveItems[key] = value; } else { //simple values copied as is ret[key] = value; } } //create list of values to censor: var censorChildItems = []; for (var key in recursiveItems) { var value = source[key]; //all complex child objects should not apear again in children: censorChildItems.push(value); } //censor all circular values for (var key in recursiveItems) { var value = source[key]; var censored = false; censorTheseItems.forEach(function (item) { if (item === value) { censored = true; } }); if (censored) { //change circular values to this value = censoredMessage; } else { //recursion: value = preventCircularJson(value, censoredMessage, censorChildItems.concat(censorTheseItems)); } ret[key] = value } return ret; }