Formatage des données JavaScript / jolie imprimante

124

J'essaie de trouver un moyen de pretty printcréer une structure de données JavaScript sous une forme lisible par l'homme pour le débogage.

J'ai une structure de données plutôt grande et compliquée stockée dans JS et j'ai besoin d'écrire du code pour la manipuler. Afin de déterminer ce que je fais et où je me trompe, ce dont j'ai vraiment besoin, c'est de pouvoir voir la structure de données dans son intégralité et de la mettre à jour chaque fois que j'apporte des modifications via l'interface utilisateur.

Je peux gérer tout cela moi-même, en plus de trouver un bon moyen de vider une structure de données JavaScript dans une chaîne lisible par l'homme. JSON ferait l'affaire, mais il doit vraiment être bien formaté et indenté. J'utiliserais généralement l'excellent contenu de déchargement DOM de Firebug pour cela, mais j'ai vraiment besoin de pouvoir voir la structure entière à la fois, ce qui ne semble pas possible dans Firebug.

Toutes les suggestions sont les bienvenues.

Merci d'avance.

Dan
la source
Je ne sais pas si vous êtes informé des modifications des réponses. J'écris donc ce commentaire pour vous informer que j'ai ajouté ma propre version de dump indenté. :-)
PhiLho
Remarque: La réponse JSON.stringify () semble être très utile, bien qu'elle ne soit pas acceptée comme «la» réponse.
GuruM
Vous pouvez obtenir une sortie visuelle et intuitive des objets en utilisant nodedump: github.com/ragamufin/nodedump
ragamufin
Jetez-y un œil: stackoverflow.com/questions/4810841/…
monkeythedev

Réponses:

31

J'ai écrit une fonction pour vider un objet JS sous une forme lisible, bien que la sortie ne soit pas indentée, mais cela ne devrait pas être trop difficile à ajouter: j'ai créé cette fonction à partir de celle que j'ai faite pour Lua (qui est beaucoup plus complexe ) qui a géré ce problème d'indentation.

Voici la version "simple":

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

Je vais chercher à l'améliorer un peu.
Remarque 1: Pour l'utiliser, faites od = DumpObject(something)et utilisez od.dump. Alambiqué parce que je voulais aussi la valeur de len (nombre d'articles) dans un autre but. Il est trivial de faire en sorte que la fonction ne renvoie que la chaîne.
Note 2: il ne gère pas les boucles dans les références.

ÉDITER

J'ai fait la version en retrait.

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

Choisissez votre indentation sur la ligne avec l'appel récursif, et accolade le style en basculant la ligne commentée après celle-ci.

... Je vois que vous avez créé votre propre version, ce qui est bien. Les visiteurs auront le choix.

PhiLho
la source
1
J'aime;) Je ne peux pas le faire fonctionner correctement, mais si cela ne vous dérange pas, je vais voler sans vergogne le concept et écrire le mien :)
Dan
2
Un inconvénient de cette approche (par rapport à la méthode JSON.stringify suggérée par Jason) est qu'elle n'affiche pas correctement les tableaux d'objets. Lorsque vous avez un tableau d'objets, il apparaît comme [objet objet].
Ryan
@Ryan: Vous parlez des objets natifs du navigateur? Oui, en regardant mon code, j'ai vu que j'avais ajouté un commentaire: // Dommage si un champ est un objet ... :-P OK pour mon test ici ... C'est OK pour vider les structures créées par l'utilisateur. Je vois qu'il existe des alternatives ci-dessous, si vous avez besoin de quelque chose de plus robuste.
PhiLho
Je ne peux pas utiliser ça. J'obtiens une boucle infinie lorsque j'essaye de vider des données json.
neoneye
1
@RaphaelDDL & PhiLho - La taille maximale de la pile d'appels peut également être déclenchée sur un petit objet; un avec une référence de propriété à lui-même. Une telle référence provoquerait une boucle infinie avec cette fonction.
skibulk
233

Utilisez le JSON.stringify de Crockford comme ceci:

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

La variable textressemblerait à ceci:

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

À propos, cela ne nécessite rien de plus que ce fichier JS - il fonctionnera avec n'importe quelle bibliothèque, etc.

Jason Bunting
la source
5
C'est presque certainement la meilleure réponse que vous obtiendrez. J'ai appris à 4 ou 5 non-programmeurs à lire et à modifier les structures de données JSON.stringified et à les utiliser intensivement pour les fichiers de configuration.
Joel Anair
1
Bizarre que cela pose des problèmes - cela introduit le nom "JSON" dans l'espace de noms global, ce qui peut vous causer des problèmes. Vérifiez votre espace de noms pour "JSON" avant d' ajouter ceci pour voir si une collision existe.
Jason Bunting
1
Eh bien, le prototype est diabolique comme ça ...;)
Jason Bunting
7
Une mise à jour à ce sujet, avec Firefox 3.5 et supérieur, JSON.stringify est intégré. ( developer.mozilla.org/En/Using_JSON_in_Firefox ), donc si vous essayez simplement de voir un objet JSON à des fins de débogage, vous pouvez le faire sans dépendances JS supplémentaires.
Greg Bernhardt le
3
Aussi dans Chrome. Cependant, JSON.stringify échoue sur les données circulaires JSON.stringify((function(){var x = []; x.push(x); return x})())et sur de nombreux autres types d'objets JSON.stringify(/foo/).
Kragen Javier Sitaker
21

Vous pouvez utiliser ce qui suit

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

Dans Firebug, si vous simplement, console.debug ("%o", my_object)vous pouvez cliquer dessus dans la console et entrer dans un explorateur d'objets interactif. Il montre l'objet entier et vous permet de développer les objets imbriqués.

John Millikin
la source
1
Le problème avec cela est qu'il ne montre que l'objet `` le plus haut '' - j'ai des dizaines d'objets imbriqués, et j'ai vraiment besoin de pouvoir voir tout le contenu à la fois, et surtout, voir où les choses changent. Donc Firebug ne fonctionne vraiment pas pour moi dans ce cas.
Dan le
(oui, je sais que vous pouvez cliquer pour les développer, mais en cliquant sur une dizaine de liens à chaque fois que je veux vider les données, c'est ce que je fais maintenant - progrès très lent)
Dan
1
Cela fonctionne également dans Chrome (et donc vraisemblablement dans Safari).
Kragen Javier Sitaker
9

Pour ceux qui recherchent un moyen génial de voir votre objet, consultez prettyPrint.js

Crée un tableau avec des options d'affichage configurables à imprimer quelque part sur votre document. Mieux vaut regarder que dans le console.

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

entrez la description de l'image ici

RaphaelDDL
la source
6

Je suis en programmation Rhinoet je n'étais satisfait d'aucune des réponses publiées ici. J'ai donc écrit ma propre jolie imprimante:

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 sortie ressemble à ceci:

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

Je l'ai également publié sous forme de Gist ici pour les modifications futures qui pourraient être nécessaires.

connaissance
la source
7
C'est peut-être une jolie imprimante mais le code n'a pas vraiment l'air très joli :)
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')
])

devient

[
   [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 (Framework de test unitaire utilisé par jQuery) utilisant une version légèrement corrigée de jsDump.


JSON.stringify () n'est pas le meilleur choix dans certains cas.

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

Prenant la direction de PhiLho (merci beaucoup :)), j'ai fini par écrire le mien car je ne pouvais pas tout à fait lui faire faire ce que je voulais. C'est assez dur et prêt, mais ça fait le travail dont j'ai besoin. Merci à tous pour les excellentes suggestions.

Ce n'est pas du code génial, je sais, mais pour ce que ça vaut, le voici. Quelqu'un pourrait le trouver utile:

// 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
la source
1
Au fait, même si vous le pouvez, vous ne devriez pas terminer les lignes sans un point-virgule. De plus, la façon standard de faire __ if (! Pad) pad = '' __ serait: __ pad = (pad || '') __
Jason Bunting
Je prends note de si (! Foo) foo = ... vs foo = (foo || ...), mais quelle est la justification pour terminer toutes les lignes par des points-virgules?
Dan
1
Vous rencontrerez des idiosyncrasies désagréables du langage si vous ne le faites pas, sans compter que vous ne pourrez pas facilement minifier votre code (à moins que le minificateur que vous utilisez soit assez agréable pour coller des points-virgules pour vous). Voir stackoverflow.com/questions/42247 pour plus de détails.
Jason Bunting
1
if (! pad) pad = ''; est moins cher, plus flexible et plus lisible que pad = (pad || ''); quoique d'une quantité infime. Si vous insistez sur cette forme, supprimez les parenthèses superflues. pad = pad || ''; 3 raisons pour les points-virgules: JS insère automatiquement des points-virgules de fin de ligne quand il voit que les omettre générerait une erreur. 1) Ceci est forcément un peu plus lent que l'ajout vous-même, et 2) peut conduire à des erreurs lorsque la ligne suivante n'arrive pas à générer une erreur lorsqu'elle est combinée. 3) empêchera votre code d'être minifié.
SamGoody
1

Ceci est vraiment juste un commentaire sur "Use Crockford's JSON.stringify" de Jason Bunting, mais je n'ai pas pu ajouter de commentaire à cette réponse.

Comme indiqué dans les commentaires, JSON.stringify ne fonctionne pas bien avec la bibliothèque Prototype (www.prototypejs.org). Cependant, il est assez facile de les faire bien jouer ensemble en supprimant temporairement la méthode Array.prototype.toJSON que le prototype ajoute, exécutez stringify () de Crockford, puis remettez-la comme ceci:

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

Je pensais que la réponse de J. Buntings sur l'utilisation de JSON.stringify était également bonne. En passant, vous pouvez utiliser JSON.stringify via l'objet JSON de YUIs si vous utilisez YUI. Dans mon cas, je devais effectuer un vidage en HTML, il était donc plus facile de modifier / couper / coller la réponse 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;
}
GTM
la source
1

Beaucoup de gens écrivent du code dans ce fil, avec de nombreux commentaires sur divers pièges. J'ai aimé cette solution car elle semblait complète et était un seul fichier sans dépendances.

navigateur

nodejs

Cela a fonctionné "hors de la boîte" et a à la fois des versions de nœud et de navigateur (probablement juste des wrappers différents mais je n'ai pas creusé pour confirmer).

La bibliothèque prend également en charge les jolies impressions XML, SQL et CSS, mais je n'ai pas essayé ces fonctionnalités.

mm2001
la source
0

Un simple pour imprimer les éléments sous forme de chaînes:

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
la source
0

Ma bibliothèque NeatJSON a à la fois des versions Ruby et JavaScript . Il est disponible gratuitement sous une licence MIT (permissive). Vous pouvez voir une démo / convertisseur en ligne à l' adresse :
http://phrogz.net/JS/neatjson/neatjson.html

Certaines fonctionnalités (toutes facultatives):

  • Envelopper à une largeur spécifique; si un objet ou un tableau peut tenir sur la ligne, il est conservé sur une seule ligne.
  • Alignez les deux points pour toutes les clés d'un objet.
  • Triez les clés d'un objet par ordre alphabétique.
  • Formatez les nombres à virgule flottante en un nombre spécifique de décimales.
  • Lors de l'encapsulation, utilisez une version «courte» qui place les crochets ouverts / fermés pour les tableaux et les objets sur la même ligne que la première / dernière valeur.
  • Contrôlez les espaces pour les tableaux et les objets de manière granulaire (entre crochets, avant / après deux points et virgules).
  • Fonctionne dans le navigateur Web et en tant que module Node.js.
Phrogz
la source
-5

flexjson inclut une fonction prettyPrint () qui peut vous donner ce que vous voulez.

Andy
la source