Domanda

Sto cercando di trovare un modo per pretty print una struttura di dati JavaScript in un formato leggibile dall'uomo per il debug.

Ho una struttura di dati piuttosto grande e complicata che viene memorizzata in JS e ho bisogno di scrivere del codice per manipolarlo. Per capire cosa sto facendo e dove sto sbagliando, ciò di cui ho davvero bisogno è poter vedere la struttura dei dati nella sua interezza e aggiornarla ogni volta che apporto modifiche attraverso l'interfaccia utente.

Tutte queste cose che posso gestire da solo, oltre a trovare un modo carino per scaricare una struttura di dati JavaScript in una stringa leggibile dall'uomo. JSON lo farebbe, ma ha davvero bisogno di essere ben formattato e rientrato. Di solito userei l'eccellente materiale di dumping DOM di Firebug per questo, ma ho davvero bisogno di essere in grado di vedere l'intera struttura in una volta, il che non sembra essere possibile in Firebug.

Eventuali suggerimenti sono benvenuti.

Grazie in anticipo.

È stato utile?

Soluzione

Ho scritto una funzione per scaricare un oggetto JS in una forma leggibile, anche se l'output non è rientrato, ma non dovrebbe essere troppo difficile aggiungerlo: ho creato questa funzione da una che ho creato per Lua (che è molto più complesso) che ha gestito questo problema di rientro.

Ecco il " semplice " Versione:

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

Cercherò di migliorarlo un po '.
Nota 1: per usarlo, fai od = DumpObject (qualcosa) e usa od.dump. Contorto perché volevo anche il valore len (numero di elementi) per un altro scopo. È banale fare in modo che la funzione restituisca solo la stringa.
Nota 2: non gestisce i loop nei riferimenti.

Modifica

Ho creato la versione rientrata.

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$/, "");
}

Scegli il rientro sulla linea con la chiamata ricorsiva e rinforza lo stile cambiando la linea commentata dopo questa.

... Vedo che hai montato la tua versione, il che è buono. I visitatori avranno una scelta.

Altri suggerimenti

Usa JSON.stringify di Crockford in questo modo:

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

Il testo della variabile sarebbe simile al seguente:

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

A proposito, questo non richiede altro che quel file JS: funzionerà con qualsiasi libreria, ecc.

Puoi usare quanto segue

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

In Firebug , se hai appena console.debug ("% o " ;, my_object) puoi fare clic su di esso nella console ed entrare in un esploratore di oggetti interattivo. Mostra l'intero oggetto e ti consente di espandere gli oggetti nidificati.

Per Node.js, utilizzare:

util.inspect(object, [options]);

Documentazione API

Per coloro che cercano un modo fantastico di vedere il tuo oggetto, controlla prettyPrint.js

Crea una tabella con opzioni di visualizzazione configurabili da stampare da qualche parte nel tuo documento. Meglio guardare che nella console .

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

inserisci qui la descrizione dell'immagine

I'm programming in Rhino and I wasn't satisfied with any of the answers that were posted here. So I've written my own pretty printer:

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

The output looks like this:

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: []
    }
}

I've also posted it as a Gist here for whatever future changes may be required.

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')
])

becomes

[
   [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 (Unit-testing framework used by jQuery) using slightly patched version of jsDump.


JSON.stringify() is not best choice on some cases.

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

Taking PhiLho's lead (thanks very much :)), I ended up writing my own as I couldn't quite get his to do what I wanted. It's pretty rough and ready, but it does the job I need. Thank you all for the excellent suggestions.

It's not brilliant code, I know, but for what it's worth, here it is. Someone might find it useful:

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

This is really just a comment on Jason Bunting's "Use Crockford's JSON.stringify", but I wasn't able to add a comment to that answer.

As noted in the comments, JSON.stringify doesn't play well with the Prototype (www.prototypejs.org) library. However, it is fairly easy to make them play well together by temporarily removing the Array.prototype.toJSON method that prototype adds, run Crockford's stringify(), then put it back like this:

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

I thought J. Buntings response on using JSON.stringify was good as well. A an aside, you can use JSON.stringify via YUIs JSON object if you happen to be using YUI. In my case I needed to dump to HTML so it was easier to just tweak/cut/paste PhiLho response.

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

Lots of people writing code in this thread, with many comments about various gotchas. I liked this solution because it seemed complete and was a single file with no dependencies.

browser

nodejs

It worked "out of the box" and has both node and browser versions (presumably just different wrappers but I didn't dig to confirm).

The library also supports pretty printing XML, SQL and CSS, but I haven't tried those features.

A simple one for printing the elements as strings:

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

My NeatJSON library has both Ruby and JavaScript versions. It is freely available under a (permissive) MIT License. You can view an online demo/converter at:
http://phrogz.net/JS/neatjson/neatjson.html

Some features (all optional):

  • Wrap to a specific width; if an object or array can fit on the line, it is kept on one line.
  • Align the colons for all keys in an object.
  • Sort the keys to an object alphabetically.
  • Format floating point numbers to a specific number of decimals.
  • When wrapping, use a 'short' version that puts the open/close brackets for arrays and objects on the same line as the first/last value.
  • Control the whitespace for arrays and objects in a granular manner (inside brackets, before/after colons and commas).
  • Works in the web browser and as a Node.js module.

flexjson includes a prettyPrint() function that might give you what you want.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top