print online array javascript json stringify

online - print json javascript



JSON.stringify objetos profundos (8)

Aquí está mi secuenciador para desmantelar JSON para el registro seguro de objetos con referencias cíclicas, elementos DOM, ámbitos angulares o ventana.

Previene TypeError: Converting circular structure to JSON reemplazando referencias circulares por ''''.

Previene RangeError: Maximum call stack size exceeded . Sin embargo, se recomienda utilizar maxDepth o filterObjects de todos modos, ya que serializar objetos muy profundos cuesta tiempo y espacio, lo que puede reducir su capacidad de uso para el registro general e incluso desconectar el navegador de prueba cuando se usa en pruebas.

Opcionalmente:

  • limita la profundidad de inspección del objeto (aún no implementado),
  • filtra objetos (como ventana, marco de prueba, corredor de prueba),
  • filtra elementos DOM,
  • filtra objetos angulares $ atributos.

Fuente + comentarios: https://gist.github.com/iki/9371373

Necesito una función que construya una cadena JSON válida de cualquier argumento pero:

  • evitando el problema de recursividad al no agregar objetos dos veces
  • evitando el problema del tamaño de la pila de llamadas al truncar más allá de una profundidad dada

En general, debería ser capaz de procesar objetos grandes, a costa de truncarlos.

Como referencia, este código falla:

var json = JSON.stringify(window);

Evitar el problema de recursividad es bastante simple:

var seen = []; return JSON.stringify(o, function(_, value) { if (typeof value === ''object'' && value !== null) { if (seen.indexOf(value) !== -1) return; else seen.push(value); } return value; });

Pero por ahora, aparte de copiar y cambiar el código de Douglas Crockford para hacer un seguimiento de la profundidad, no encontré ninguna manera de evitar el desbordamiento de la pila en objetos muy profundos como window o cualquier event . ¿Hay una solución simple?


Creo que el formato que estás utilizando no es justo para hacer lo que quieres. Al obtener todos los datos contenidos en el objeto de la ventana en una sola cadena JSON, supongamos que mantiene esta cadena en la memoria durante el desarrollo de los problemas que le ocasionaron.

Necesita un formato que le brinde la capacidad de enviar datos a medida que se analiza desde el objeto de la ventana para liberar memoria sobre la marcha. Para el caso, debería usar algo como CSV, Text o VarStream ( https://github.com/nfroidure/VarStream ).

También podría iterar a través del objeto e intentar JSON.stringify en un try ... catch. Si la prueba es exitosa, envíe el archivo JSON; si falla, iterará por las propiedades del objeto con el mismo intento ... atrape etc ... Pero es una solución fea que no le recomiendo usar.


Hice lo que inicialmente temí que tendría que hacer: tomé el código de Crockford y lo modifiqué para mis necesidades. Ahora construye JSON pero maneja

  • ciclos
  • objetos demasiado profundos
  • matrices demasiado largas
  • excepciones (acceso a los que no se puede acceder legalmente)

En caso de que alguien lo necesite, hice un repositorio de GitHub: JSON.prune en GitHub

Aquí está el código:

// JSON.pruned : a function to stringify any object without overflow // example : var json = JSON.pruned({a:''e'', c:[1,2,{d:{e:42, f:''deep''}}]}) // two additional optional parameters : // - the maximal depth (default : 6) // - the maximal length of arrays (default : 50) // GitHub : https://github.com/Canop/JSON.prune // This is based on Douglas Crockford''s code ( https://github.com/douglascrockford/JSON-js/blob/master/json2.js ) (function () { ''use strict''; var DEFAULT_MAX_DEPTH = 6; var DEFAULT_ARRAY_MAX_LENGTH = 50; var seen; // Same variable used for all stringifications Date.prototype.toPrunedJSON = Date.prototype.toJSON; String.prototype.toPrunedJSON = String.prototype.toJSON; var cx = /[/u0000/u00ad/u0600-/u0604/u070f/u17b4/u17b5/u200c-/u200f/u2028-/u202f/u2060-/u206f/ufeff/ufff0-/uffff]/g, escapable = /[///"/x00-/x1f/x7f-/x9f/u00ad/u0600-/u0604/u070f/u17b4/u17b5/u200c-/u200f/u2028-/u202f/u2060-/u206f/ufeff/ufff0-/uffff]/g, meta = { // table of character substitutions ''/b'': ''//b'', ''/t'': ''//t'', ''/n'': ''//n'', ''/f'': ''//f'', ''/r'': ''//r'', ''"'' : ''//"'', ''//': ''////' }; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? ''"'' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === ''string'' ? c : ''//u'' + (''0000'' + a.charCodeAt(0).toString(16)).slice(-4); }) + ''"'' : ''"'' + string + ''"''; } function str(key, holder, depthDecr, arrayMaxLength) { var i, // The loop counter. k, // The member key. v, // The member value. length, partial, value = holder[key]; if (value && typeof value === ''object'' && typeof value.toPrunedJSON === ''function'') { value = value.toPrunedJSON(key); } switch (typeof value) { case ''string'': return quote(value); case ''number'': return isFinite(value) ? String(value) : ''null''; case ''boolean'': case ''null'': return String(value); case ''object'': if (!value) { return ''null''; } if (depthDecr<=0 || seen.indexOf(value)!==-1) { return ''"-pruned-"''; } seen.push(value); partial = []; if (Object.prototype.toString.apply(value) === ''[object Array]'') { length = Math.min(value.length, arrayMaxLength); for (i = 0; i < length; i += 1) { partial[i] = str(i, value, depthDecr-1, arrayMaxLength) || ''null''; } v = partial.length === 0 ? ''[]'' : ''['' + partial.join('','') + '']''; return v; } for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { try { v = str(k, value, depthDecr-1, arrayMaxLength); if (v) partial.push(quote(k) + '':'' + v); } catch (e) { // this try/catch due to some "Accessing selectionEnd on an input element that cannot have a selection." on Chrome } } } v = partial.length === 0 ? ''{}'' : ''{'' + partial.join('','') + ''}''; return v; } } JSON.pruned = function (value, depthDecr, arrayMaxLength) { seen = []; depthDecr = depthDecr || DEFAULT_MAX_DEPTH; arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH; return str('''', {'''': value}, depthDecr, arrayMaxLength); }; }());

Un ejemplo de lo que se puede hacer:

var json = JSON.pruned(window);

Nota: Al contrario del código en esta respuesta, el repositorio de GitHub se actualiza cuando es necesario (documentación, compatibilidad, uso como módulo en commonjs o nodo, serializaciones específicas, etc.). Es una buena idea comenzar desde el repositorio si necesita esta característica de poda.


Podrías mantener la profundidad en la que estás:

function stringify(obj, currentDepth, maxDepth) { if (currentDepth == maxDepth) return ''[Warning: max level reached]'' var str = ''{''; for (var key in obj) { str += key + '': '' + typeof obj == ''object'' ? stringify(obj[key], currentDepth + 1, maxDepth) : obj[key]; } return str + ''}'' }

(solo ejemplo, obviamente este fragmento no detecta la recursividad)


Revisé la respuesta de @distroy y agregué:

  • Sangría para sub-propiedades.
  • Una indicación de hacia dónde apuntan las referencias circulares.

/** * Returns the JSON representation of an object. * * @param {value} object the object * @param {number} objectMaxDepth for objects, the maximum number of times to recurse into descendants * @param {number} arrayMaxLength for arrays, the maximum number of elements to enumerate * @param {string} indent the string to use for indentation * @return {string} the JSON representation */ var toJSON = function(object, objectMaxDepth, arrayMaxLength, indent) { "use strict"; /** * Escapes control characters, quote characters, backslash characters and quotes the string. * * @param {string} string the string to quote * @returns {String} the quoted string */ function quote(string) { escapable.lastIndex = 0; var escaped; if (escapable.test(string)) { escaped = string.replace(escapable, function(a) { var replacement = replacements[a]; if (typeof (replacement) === "string") return replacement; // Pad the unicode representation with leading zeros, up to 4 characters. return "//u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }); } else escaped = string; return "/"" + escaped + "/""; } /** * Returns the String representation of an object. * * Based on <a href="https://github.com/Canop/JSON.prune/blob/master/JSON.prune.js">https://github.com/Canop/JSON.prune/blob/master/JSON.prune.js</a> * * @param {string} path the fully-qualified path of value in the JSON object * @param {type} value the value of the property * @param {string} cumulativeIndent the indentation to apply at this level * @param {number} depth the current recursion depth * @return {String} the JSON representation of the object, or "null" for values that aren''t valid * in JSON (e.g. infinite numbers). */ function toString(path, value, cumulativeIndent, depth) { switch (typeof (value)) { case "string": return quote(value); case "number": { // JSON numbers must be finite if (isFinite(value)) return String(value); return "null"; } case "boolean": return String(value); case "object": { if (!value) return "null"; var valueIndex = values.indexOf(value); if (valueIndex !== -1) return "Reference => " + paths[valueIndex]; values.push(value); paths.push(path); if (depth > objectMaxDepth) return "..."; // Make an array to hold the partial results of stringifying this object value. var partial = []; // Is the value an array? var i; if (Object.prototype.toString.apply(value) === "[object Array]") { // The value is an array. Stringify every element var length = Math.min(value.length, arrayMaxLength); // Whether a property has one or multiple values, they should be treated as the same // object depth. As such, we do not increment the object depth when recursing into an // array. for (i = 0; i < length; ++i) { partial[i] = toString(path + "." + i, value[i], cumulativeIndent + indent, depth, arrayMaxLength); } if (i < value.length) { // arrayMaxLength reached partial[i] = "..."; } return "/n" + cumulativeIndent + "[" + partial.join(", ") + "/n" + cumulativeIndent + "]"; } // Otherwise, iterate through all of the keys in the object. for (var subKey in value) { if (Object.prototype.hasOwnProperty.call(value, subKey)) { var subValue; try { subValue = toString(path + "." + subKey, value[subKey], cumulativeIndent + indent, depth + 1); partial.push(quote(subKey) + ": " + subValue); } catch (e) { // this try/catch due to forbidden accessors on some objects if (e.message) subKey = e.message; else subKey = "access denied"; } } } var result = "/n" + cumulativeIndent + "{/n"; for (i = 0; i < partial.length; ++i) result += cumulativeIndent + indent + partial[i] + ",/n"; if (partial.length > 0) { // Remove trailing comma result = result.slice(0, result.length - 2) + "/n"; } result += cumulativeIndent + "}"; return result; } default: return "null"; } } if (indent === undefined) indent = " "; if (objectMaxDepth === undefined) objectMaxDepth = 0; if (arrayMaxLength === undefined) arrayMaxLength = 50; // Matches characters that must be escaped var escapable = /[///"/x00-/x1f/x7f-/x9f/u00ad/u0600-/u0604/u070f/u17b4/u17b5/u200c-/u200f/u2028-/u202f/u2060-/u206f/ufeff/ufff0-/uffff]/g; // The replacement characters var replacements = { "/b": "//b", "/t": "//t", "/n": "//n", "/f": "//f", "/r": "//r", "/"": "///"", "//": "////" }; // A list of all the objects that were seen (used to avoid recursion) var values = []; // The path of an object in the JSON object, with indexes corresponding to entries in the // "values" variable. var paths = []; return toString("root", object, "", 0); };


Si está utilizando Node.js, puede usar util.inspect , que toma un argumento de profundidad.


Simplemente puede usar una función de Censor como en el siguiente ejemplo:

function censor(key, value) { if (typeof(value) == "string") { return undefined; } return value; } var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7}; var jsonString = JSON.stringify(foo, censor);

La salida es {"week":45,"month":7} .

Por lo que respecta a su ejemplo, debe devolver indefinido si tiene un objeto de valor, que es una ventana.


(function (input, level) { if (!input) return input; level = level || 4; var objectsAlreadySerialized = [input], objDepth = [input]; return JSON.stringify(input, function (key, value) { if (key) { if (typeof value === ''object'') { if (objectsAlreadySerialized.indexOf(value) !== -1) return undefined; objectsAlreadySerialized.push(value); } if (objDepth.indexOf(this) === -1) objDepth.push(this); else while(objDepth[objDepth.length-1] !== this) objDepth.pop(); if (objDepth.length > level) return undefined; } return value; }); })(window, 6)