Pregunta

Estoy tratando de encontrar una manera de impresión bonita una estructura de datos de JavaScript en una forma legible por humanos para la depuración.

Tengo una estructura de datos bastante grande y complicada que se almacena en JS y necesito escribir un código para manipularlo. Para descubrir lo que estoy haciendo y lo que hago mal, lo que realmente necesito es poder ver la estructura de datos en su totalidad y actualizarla cada vez que realice cambios a través de la interfaz de usuario.

Todas estas cosas las puedo manejar por mi cuenta, además de encontrar una buena manera de volcar una estructura de datos de JavaScript en una cadena legible por humanos. JSON lo haría, pero realmente necesita estar bien formateado y con sangría. Usualmente uso el excelente material de volcado de DOM de Firebug para esto, pero realmente necesito poder ver toda la estructura a la vez, lo que no parece ser posible en Firebug.

Cualquier sugerencia es bienvenida.

Gracias de antemano.

¿Fue útil?

Solución

Escribí una función para volcar un objeto JS en una forma legible, aunque la salida no tiene sangría, pero no debería ser muy difícil agregar eso: hice esta función a partir de una que hice para Lua (que es mucho más complejo) que manejó este problema de sangría.

Aquí está el " simple " versión:

function DumpObject(obj)
{
  var od = new Object;
  var result = "";
  var len = 0;

  for (var property in obj)
  {
    var value = obj[property];
    if (typeof value == 'string')
      value = "'" + value + "'";
    else if (typeof value == 'object')
    {
      if (value instanceof Array)
      {
        value = "[ " + value + " ]";
      }
      else
      {
        var ood = DumpObject(value);
        value = "{ " + ood.dump + " }";
      }
    }
    result += "'" + property + "' : " + value + ", ";
    len++;
  }
  od.dump = result.replace(/, $/, "");
  od.len = len;

  return od;
}

Veré cómo mejorarlo un poco.
Nota 1: Para usarlo, haga od = DumpObject (algo) y use od.dump. Enrevesado porque también quería el valor de len (número de elementos) para otro propósito. Es trivial hacer que la función devuelva solo la cadena.
Nota 2: no maneja los bucles en las referencias.

EDIT

Hice la versión con sangría.

function DumpObjectIndented(obj, indent)
{
  var result = "";
  if (indent == null) indent = "";

  for (var property in obj)
  {
    var value = obj[property];
    if (typeof value == 'string')
      value = "'" + value + "'";
    else if (typeof value == 'object')
    {
      if (value instanceof Array)
      {
        // Just let JS convert the Array to a string!
        value = "[ " + value + " ]";
      }
      else
      {
        // Recursive dump
        // (replace "  " by "\t" or something else if you prefer)
        var od = DumpObjectIndented(value, indent + "  ");
        // If you like { on the same line as the key
        //value = "{\n" + od + "\n" + indent + "}";
        // If you prefer { and } to be aligned
        value = "\n" + indent + "{\n" + od + "\n" + indent + "}";
      }
    }
    result += indent + "'" + property + "' : " + value + ",\n";
  }
  return result.replace(/,\n$/, "");
}

Elija su sangría en la línea con la llamada recursiva, y ajuste el estilo cambiando la línea comentada después de esta.

... Veo que preparaste tu propia versión, lo cual es bueno. Los visitantes tendrán una opción.

Otros consejos

Utilice JSON.stringify de Crockford me gusta esto:

var myArray = ['e', {pluribus: 'unum'}];
var text = JSON.stringify(myArray, null, '\t'); //you can specify a number instead of '\t' and that many spaces will be used for indentation...

El texto variable se vería así:

[
  "e",
   {
      "pluribus": "unum"
   }
]

Por cierto, esto no requiere nada más que ese archivo JS: funcionará con cualquier biblioteca, etc.

Puedes usar lo siguiente

<pre id="dump"></pre>
<script>
   var dump = JSON.stringify(sampleJsonObject, null, 4); 
   $('#dump').html(dump)
</script>

En Firebug , si solo console.debug ("% o " ;, my_object) puede hacer clic en él en la consola e ingresar a un explorador de objetos interactivo. Muestra el objeto completo y le permite expandir objetos anidados.

Para Node.js, use:

util.inspect(object, [options]);

Documentación de API

Para aquellos que buscan una manera increíble de ver su objeto, ver prettyPrint.js

Crea una tabla con opciones de vista configurables para imprimir en algún lugar de su documento. Es mejor mirar que en la consola .

var tbl = prettyPrint( myObject, { /* options such as maxDepth, etc. */ });
document.body.appendChild(tbl);

ingrese la descripción de la imagen aquí

Estoy programando en Rhino y no estaba satisfecho con ninguna de las respuestas que se publicaron aquí. Así que he escrito mi propia impresora bonita:

function pp(object, depth, embedded) { 
  typeof(depth) == "number" || (depth = 0)
  typeof(embedded) == "boolean" || (embedded = false)
  var newline = false
  var spacer = function(depth) { var spaces = ""; for (var i=0;i<depth;i++) { spaces += "  "}; return spaces }
  var pretty = ""
  if (      typeof(object) == "undefined" ) { pretty += "undefined" }
  else if ( typeof(object) == "boolean" || 
            typeof(object) == "number" ) {    pretty += object.toString() } 
  else if ( typeof(object) == "string" ) {    pretty += "\"" + object + "\"" } 
  else if (        object  == null) {         pretty += "null" } 
  else if ( object instanceof(Array) ) {
    if ( object.length > 0 ) {
      if (embedded) { newline = true }
      var content = ""
      for each (var item in object) { content += pp(item, depth+1) + ",\n" + spacer(depth+1) }
      content = content.replace(/,\n\s*$/, "").replace(/^\s*/,"")
      pretty += "[ " + content + "\n" + spacer(depth) + "]"
    } else { pretty += "[]" }
  } 
  else if (typeof(object) == "object") {
    if ( Object.keys(object).length > 0 ){
      if (embedded) { newline = true }
      var content = ""
      for (var key in object) { 
        content += spacer(depth + 1) + key.toString() + ": " + pp(object[key], depth+2, true) + ",\n" 
      }
      content = content.replace(/,\n\s*$/, "").replace(/^\s*/,"")
      pretty += "{ " + content + "\n" + spacer(depth) + "}"
    } else { pretty += "{}"}
  }
  else { pretty += object.toString() }
  return ((newline ? "\n" + spacer(depth) : "") + pretty)
}

La salida se ve así:

js> pp({foo:"bar", baz: 1})
{ foo: "bar",
  baz: 1
}
js> var taco
js> pp({foo:"bar", baz: [1,"taco",{"blarg": "moo", "mine": "craft"}, null, taco, {}], bleep: {a:null, b:taco, c: []}})
{ foo: "bar",
  baz: 
    [ 1,
      "taco",
      { blarg: "moo",
        mine: "craft"
      },
      null,
      undefined,
      {}
    ],
  bleep: 
    { a: null,
      b: undefined,
      c: []
    }
}

También lo publiqué como Gist here para cualquier cambio futuro que pueda ser necesario.

jsDump

jsDump.parse([
    window,
    document,
    { a : 5, '1' : 'foo' },
    /^[ab]+$/g,
    new RegExp('x(.*?)z','ig'),
    alert, 
    function fn( x, y, z ){
        return x + y; 
    },
    true,
    undefined,
    null,
    new Date(),
    document.body,
    document.getElementById('links')
])

se convierte en

[
   [Window],
   [Document],
   {
      "1": "foo",
      "a": 5
   },
   /^[ab]+$/g,
   /x(.*?)z/gi,
   function alert( a ){
      [code]
   },
   function fn( a, b, c ){
      [code]
   },
   true,
   undefined,
   null,
   "Fri Feb 19 2010 00:49:45 GMT+0300 (MSK)",
   <body id="body" class="node"></body>,
   <div id="links">
]

QUnit (marco de prueba de unidades utilizado por jQuery) con una versión ligeramente parcheada de jsDump.


JSON.stringify () no es la mejor opción en algunos casos.

JSON.stringify({f:function(){}}) // "{}"
JSON.stringify(document.body)    // TypeError: Converting circular structure to JSON

Tomando el liderazgo de PhiLho (muchas gracias :)), terminé escribiendo el mío, ya que no podía hacer que él hiciera lo que quería. Es bastante difícil y está listo, pero hace el trabajo que necesito. Gracias a todos por las excelentes sugerencias.

No es un código brillante, lo sé, pero para lo que vale, aquí está. Alguien podría encontrarlo útil:

// Usage: dump(object)
function dump(object, pad){
    var indent = '\t'
    if (!pad) pad = ''
    var out = ''
    if (object.constructor == Array){
        out += '[\n'
        for (var i=0; i<object.length; i++){
            out += pad + indent + dump(object[i], pad + indent) + '\n'
        }
        out += pad + ']'
    }else if (object.constructor == Object){
        out += '{\n'
        for (var i in object){
            out += pad + indent + i + ': ' + dump(object[i], pad + indent) + '\n'
        }
        out += pad + '}'
    }else{
        out += object
    }
    return out
}

Esto es realmente solo un comentario sobre Jason Bunting "Use Crockford's JSON.stringify", pero no pude agregar un comentario a esa respuesta.

Como se señaló en los comentarios, JSON.stringify no juega bien con la biblioteca Prototype (www.prototypejs.org). Sin embargo, es bastante fácil hacer que jueguen bien juntos eliminando temporalmente el método Array.prototype.toJSON que agrega el prototipo, ejecute Strockford's stringify (), luego vuelva a ponerlo así:

  var temp = Array.prototype.toJSON;
  delete Array.prototype.toJSON;
  $('result').value += JSON.stringify(profile_base, null, 2);
  Array.prototype.toJSON = temp;

Pensé que la respuesta de J. Buntings sobre el uso de JSON.stringify también era buena. Además, puedes usar JSON.stringify a través del objeto JSON de YUIs si estás usando YUI. En mi caso, tenía que volcar en HTML, así que era más fácil simplemente ajustar / cortar / pegar la respuesta de PhiLho.

function dumpObject(obj, indent) 
{
  var CR = "<br />", SPC = "&nbsp;&nbsp;&nbsp;&nbsp;", result = "";
  if (indent == null) indent = "";

  for (var property in obj)
  {
    var value = obj[property];

    if (typeof value == 'string')
    {
      value = "'" + value + "'";
    }
    else if (typeof value == 'object')
    {
      if (value instanceof Array)
      {
        // Just let JS convert the Array to a string!
        value = "[ " + value + " ]";
      }
      else
      {
        var od = dumpObject(value, indent + SPC);
        value = CR + indent + "{" + CR + od + CR + indent + "}";
      }
    }
    result += indent + "'" + property + "' : " + value + "," + CR;
  }
  return result;
}

Mucha gente escribe código en este hilo, con muchos comentarios sobre varios errores. Me gustó esta solución porque parecía completa y era un solo archivo sin dependencias.

browser

nodejs

Funcionó " fuera de la caja " y tiene versiones de nodo y navegador (presumiblemente solo envoltorios diferentes pero no hice pruebas para confirmar).

La biblioteca también admite la impresión bonita de XML, SQL y CSS, pero no he probado esas características.

Uno simple para imprimir los elementos como cadenas:

var s = "";
var len = array.length;
var lenMinus1 = len - 1
for (var i = 0; i < len; i++) {
   s += array[i];
   if(i < lenMinus1)  {
      s += ", ";
   }
}
alert(s);

Mi biblioteca NeatJSON tiene tanto Ruby como versiones de JavaScript . Está disponible gratuitamente bajo una licencia (permisiva) de MIT. Puede ver una demostración / convertidor en línea en:
http://phrogz.net/JS/neatjson/neatjson.html

Algunas características (todas opcionales):

  • Ajustar a un ancho específico; si un objeto o matriz puede caber en la línea, se mantiene en una línea.
  • Alinear los dos puntos para todas las claves en un objeto.
  • Ordena las claves de un objeto alfabéticamente.
  • Dar formato a números de coma flotante a un número específico de decimales.
  • Al envolver, use una versión 'corta' que coloque los corchetes de apertura / cierre para matrices y objetos en la misma línea que el primer / último valor.
  • Controle el espacio en blanco para matrices y objetos de forma granular (entre corchetes, antes y después de dos puntos y comas).
  • Funciona en el navegador web y como módulo Node.js.

flexjson incluye una función prettyPrint () eso podría darte lo que quieres.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top