JavaScript-Datenformatierung / hübscher Drucker

124

Ich versuche, einen Weg zu pretty printeiner JavaScript-Datenstruktur in lesbarer Form zum Debuggen zu finden.

Ich habe eine ziemlich große und komplizierte Datenstruktur, die in JS gespeichert ist, und ich muss Code schreiben, um sie zu manipulieren. Um herauszufinden, was ich tue und wo ich falsch liege, muss ich wirklich in der Lage sein, die Datenstruktur in ihrer Gesamtheit zu sehen und sie zu aktualisieren, wenn ich Änderungen über die Benutzeroberfläche vornehme.

All diese Dinge kann ich selbst erledigen, abgesehen davon, dass ich einen guten Weg gefunden habe, eine JavaScript-Datenstruktur in eine für Menschen lesbare Zeichenfolge zu kopieren. JSON würde es tun, aber es muss wirklich gut formatiert und eingerückt sein. Normalerweise würde ich dafür Firebugs exzellentes DOM-Dumping-Material verwenden, aber ich muss wirklich in der Lage sein, die gesamte Struktur auf einmal zu sehen, was in Firebug nicht möglich zu sein scheint.

Anregungen sind willkommen.

Danke im Voraus.

Dan
quelle
Ich bin mir nicht sicher, ob Sie über Änderungen der Antworten informiert werden. Deshalb schreibe ich diesen Kommentar, um Sie darüber zu informieren, dass ich meine eigene Version des eingerückten Dumps hinzugefügt habe. :-)
PhiLho
Hinweis: Die Antwort JSON.stringify () scheint sehr nützlich zu sein, wird jedoch nicht als "die" Antwort akzeptiert.
GuruM
Sie könnten eine visuelle und intuitive Ausgabe von Objekten mit nodedump erhalten: github.com/ragamufin/nodedump
ragamufin
Schauen Sie dort nach: stackoverflow.com/questions/4810841/…
monkeythedev

Antworten:

31

Ich habe eine Funktion geschrieben, um ein JS-Objekt in lesbarer Form zu sichern, obwohl die Ausgabe nicht eingerückt ist, aber es sollte nicht zu schwierig sein, dies hinzuzufügen: Ich habe diese Funktion aus einer für Lua erstellten Funktion erstellt (die viel komplexer ist) ), die dieses Einrückungsproblem behandelt haben.

Hier ist die "einfache" Version:

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

Ich werde versuchen, es ein bisschen zu verbessern.
Hinweis 1: Um es zu verwenden, führen Sie od = DumpObject(something)od.dump aus. Gewunden, weil ich den len-Wert (Anzahl der Elemente) auch für einen anderen Zweck haben wollte. Es ist trivial, die Funktion nur die Zeichenfolge zurückgeben zu lassen.
Hinweis 2: Es werden keine Schleifen in Referenzen behandelt.

BEARBEITEN

Ich habe die eingerückte Version gemacht.

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

Wählen Sie Ihre Einrückung in der Zeile mit dem rekursiven Aufruf aus, und Sie klammern den Stil, indem Sie die kommentierte Zeile nach dieser umschalten.

... Ich sehe, du hast deine eigene Version entwickelt, was gut ist. Besucher haben die Wahl.

PhiLho
quelle
1
Ich mag;) Kann es nicht richtig zum Laufen bringen, aber wenn es dir nichts ausmacht, werde ich schamlos das Konzept stehlen und mein eigenes schreiben :)
Dan
2
Ein kurzes Ergebnis dieses Ansatzes (verglichen mit der von Jason vorgeschlagenen JSON.stringify-Methode) ist, dass Arrays von Objekten nicht richtig angezeigt werden. Wenn Sie ein Array von Objekten haben, wird es als [Objekt Objekt] angezeigt.
Ryan
@ Ryan: Du meinst die nativen Objekte des Browsers? Ja, als ich auf meinen Code zurückblickte, sah ich, dass ich einen Kommentar hinzugefügt habe: // Schade, wenn ein Feld ein Objekt ist ... :-P OK für meinen Test hier ... Es ist in Ordnung, benutzerdefinierte Strukturen zu sichern. Ich sehe unten Alternativen, wenn Sie etwas Robusteres brauchen.
PhiLho
Ich kann das nicht benutzen. Ich bekomme eine Endlosschleife, wenn ich versuche, einige JSON-Daten zu sichern.
Neoneye
1
@RaphaelDDL & PhiLho - Die maximale Aufrufstapelgröße kann auch für ein kleines Objekt ausgelöst werden. eine mit einem Eigenschaftsverweis auf sich selbst. Eine solche Referenz würde mit dieser Funktion eine Endlosschleife verursachen.
Skibulk
233

Verwenden Sie Crockfords JSON.stringify wie folgt :

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

Variable textwürde so aussehen:

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

Dies erfordert übrigens nichts weiter als diese JS-Datei - sie funktioniert mit jeder Bibliothek usw.

Jason Bunting
quelle
5
Dies ist mit ziemlicher Sicherheit die beste Antwort, die Sie erhalten werden. Ich habe 4 oder 5 Nicht-Programmierern beigebracht, JSON.stringified-Datenstrukturen zu lesen, zu bearbeiten und sie ausgiebig für Konfigurationsdateien zu verwenden.
Joel Anair
1
Seltsam, dass es Probleme verursachen würde - es führt den Namen "JSON" in den globalen Namespace ein, so dass Sie Probleme verursachen können. Überprüfen Sie Ihren Namespace auf "JSON", bevor Sie diesen hinzufügen, um festzustellen, ob eine Kollision vorliegt.
Jason Bunting
1
Nun, Prototyp ist so böse ...;)
Jason Bunting
7
Ein Update dazu mit Firefox 3.5 und höher, JSON.stringify, ist integriert. ( developer.mozilla.org/En/Using_JSON_in_Firefox ) Wenn Sie also nur versuchen, ein JSON-Objekt für Debugging-Zwecke anzuzeigen, können Sie dies ohne zusätzliche JS-Abhängigkeiten tun.
Greg Bernhardt
3
Auch in Chrome. JSON.stringify schlägt jedoch bei zirkulären Daten JSON.stringify((function(){var x = []; x.push(x); return x})())und bei vielen anderen Arten von Objekten fehl JSON.stringify(/foo/).
Kragen Javier Sitaker
21

Sie können Folgendes verwenden

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

In Firebug, wenn Sie nur console.debug ("%o", my_object)können Sie in der Konsole darauf klicken und ein interaktives Objekt - Explorer eingeben. Es zeigt das gesamte Objekt und ermöglicht das Erweitern verschachtelter Objekte.

John Millikin
quelle
1
Das Problem dabei ist, dass nur das 'oberste' Objekt angezeigt wird - ich habe Dutzende verschachtelter Objekte, und ich muss wirklich in der Lage sein, den gesamten Inhalt auf einmal zu sehen und vor allem zu sehen, wo sich die Dinge ändern. Firebug funktioniert in diesem Fall also wirklich nicht für mich.
Dan
(Ja, ich weiß, dass Sie klicken können, um sie zu erweitern, aber wenn ich jedes Mal, wenn ich die Daten sichern möchte, auf etwa 10 Links klicke, mache ich das jetzt - sehr langsamer Fortschritt)
Dan
1
Dies funktioniert auch in Chrome (und daher vermutlich in Safari).
Kragen Javier Sitaker
9

Für diejenigen, die nach einer großartigen Möglichkeit suchen, Ihr Objekt zu sehen, besuchen Sie prettyPrint.js

Erstellt eine Tabelle mit konfigurierbaren Ansichtsoptionen, die irgendwo in Ihrem Dokument gedruckt werden sollen. Besser zu schauen als in der console.

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

Geben Sie hier die Bildbeschreibung ein

RaphaelDDL
quelle
6

Ich programmiere gerade Rhinound war mit keiner der hier veröffentlichten Antworten zufrieden. Also habe ich meinen eigenen hübschen Drucker geschrieben:

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

Die Ausgabe sieht folgendermaßen aus:

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

Ich habe es hier auch als Zusammenfassung für zukünftige Änderungen veröffentlicht.

Knowtheory
quelle
7
Es könnte ein hübscher Drucker sein, aber der Code sieht eigentlich nicht sehr hübsch aus :)
Xion
3

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

wird

[
   [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 von jQuery) mit leicht gepatchter Version von jsDump.


JSON.stringify () ist in einigen Fällen nicht die beste Wahl.

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

Ich übernahm PhiLhos Führung (vielen Dank :)) und schrieb schließlich meine eigene, da ich seine nicht dazu bringen konnte, das zu tun, was ich wollte. Es ist ziemlich rau und bereit, aber es macht den Job, den ich brauche. Vielen Dank für die hervorragenden Vorschläge.

Ich weiß, es ist kein brillanter Code, aber für das, was es wert ist, hier ist es. Jemand könnte es nützlich finden:

// 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
}
Dan
quelle
1
Übrigens, obwohl Sie können, sollten Sie Zeilen nicht ohne Semikolon beenden. Die Standardmethode für __ if (! Pad) pad = '' __ wäre: __ pad = (pad || '') __
Jason Bunting
Ich nehme an, wenn (! Foo) foo = ... vs foo = (foo || ...), aber was ist der Grund dafür, alle Zeilen mit Semikolons zu beenden?
Dan
1
Wenn Sie dies nicht tun, werden Sie auf einige unangenehme Besonderheiten der Sprache stoßen, ganz zu schweigen davon, dass Sie Ihren Code nicht einfach minimieren können (es sei denn, der von Ihnen verwendete Minifier ist nett genug, um Semikolons für Sie einzufügen). Weitere Informationen finden Sie unter stackoverflow.com/questions/42247 .
Jason Bunting
1
if (! pad) pad = ''; ist billiger, flexibler und lesbarer als pad = (pad || ''); wenn auch um eine Minute. Wenn Sie auf diesem Formular bestehen, entfernen Sie die überflüssige Klammer. pad = pad || ''; 3 Gründe für Semikolons: JS fügt Endzeilensemikolons automatisch ein, wenn festgestellt wird, dass das Auslassen dieser Semikolons einen Fehler auslösen würde. 1) Dies ist zwangsläufig ein kleines bisschen langsamer als das Hinzufügen selbst, und 2) kann zu Fehlern führen, wenn die nächste Zeile in Kombination keinen Fehler auslöst. 3) verhindert, dass Ihr Code minimiert wird.
SamGoody
1

Dies ist wirklich nur ein Kommentar zu Jason Bunting "Use Crockford's JSON.stringify", aber ich konnte dieser Antwort keinen Kommentar hinzufügen.

Wie in den Kommentaren erwähnt, funktioniert JSON.stringify nicht gut mit der Prototype-Bibliothek (www.prototypejs.org). Es ist jedoch ziemlich einfach, sie gut zusammenspielen zu lassen, indem Sie die vom Prototyp hinzugefügte Array.prototype.toJSON-Methode vorübergehend entfernen, Crockfords stringify () ausführen und dann wie folgt zurücksetzen:

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

Ich fand die Reaktion von J. Buntings auf die Verwendung von JSON.stringify ebenfalls gut. Abgesehen davon können Sie JSON.stringify über das JSON-Objekt von YUIs verwenden, wenn Sie zufällig YUI verwenden. In meinem Fall musste ich in HTML sichern, damit es einfacher war, die PhiLho-Antwort zu optimieren / auszuschneiden / einzufügen.

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;
}
GTM
quelle
1

Viele Leute schreiben Code in diesen Thread, mit vielen Kommentaren zu verschiedenen Fallstricken. Ich mochte diese Lösung, weil sie vollständig schien und eine einzelne Datei ohne Abhängigkeiten war.

Browser

nodejs

Es funktionierte "out of the box" und hat sowohl Knoten- als auch Browserversionen (vermutlich nur verschiedene Wrapper, aber ich habe nicht gegraben, um dies zu bestätigen).

Die Bibliothek unterstützt auch hübsches Drucken von XML, SQL und CSS, aber ich habe diese Funktionen nicht ausprobiert.

mm2001
quelle
0

Ein einfaches zum Drucken der Elemente als Zeichenfolgen:

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);
aliteralmind
quelle
0

Meine NeatJSON- Bibliothek enthält sowohl Ruby- als auch JavaScript-Versionen . Es ist unter einer (zulässigen) MIT-Lizenz frei verfügbar. Sie können eine Online-Demo / Konverter unter folgender Adresse anzeigen:
http://phrogz.net/JS/neatjson/neatjson.html

Einige Funktionen (alle optional):

  • Auf eine bestimmte Breite einwickeln; Wenn ein Objekt oder Array in die Zeile passt, wird es in einer Zeile gehalten.
  • Richten Sie die Doppelpunkte für alle Schlüssel in einem Objekt aus.
  • Sortieren Sie die Schlüssel zu einem Objekt alphabetisch.
  • Formatieren Sie Gleitkommazahlen auf eine bestimmte Anzahl von Dezimalstellen.
  • Verwenden Sie beim Umbrechen eine 'kurze' Version, bei der die Klammern zum Öffnen / Schließen von Arrays und Objekten in derselben Zeile wie der erste / letzte Wert stehen.
  • Steuern Sie das Leerzeichen für Arrays und Objekte detailliert (in Klammern, vor / nach Doppelpunkten und Kommas).
  • Funktioniert im Webbrowser und als Node.js-Modul.
Phrogz
quelle
-5

flexjson enthält eine hübschePrint () - Funktion, mit der Sie möglicherweise das bekommen, was Sie wollen.

Andy
quelle