Memformat data JavaScript / printer cantik

124

Saya mencoba menemukan cara untuk pretty printstruktur data JavaScript dalam bentuk yang dapat dibaca manusia untuk debugging.

Saya memiliki struktur data yang agak besar dan rumit yang disimpan di JS dan saya perlu menulis beberapa kode untuk memanipulasinya. Untuk mengetahui apa yang saya lakukan dan di mana kesalahan saya, yang benar-benar saya butuhkan adalah untuk dapat melihat struktur data secara keseluruhan, dan memperbaruinya setiap kali saya melakukan perubahan melalui UI.

Semua hal ini dapat saya tangani sendiri, selain dari menemukan cara yang bagus untuk membuang struktur data JavaScript ke string yang dapat dibaca manusia. JSON akan melakukannya, tetapi itu benar-benar perlu diformat dan indentasi dengan baik. Saya biasanya menggunakan barang-barang DOM Firebug yang sangat baik untuk ini, tetapi saya benar-benar harus dapat melihat seluruh struktur sekaligus, yang sepertinya tidak mungkin di Firebug.

Setiap saran dipersilahkan.

Terima kasih sebelumnya.

Dan
sumber
Tidak yakin apakah Anda diberi tahu tentang suntingan jawaban. Jadi saya menulis komentar ini untuk memberi tahu Anda bahwa saya telah menambahkan versi indentasi dump saya sendiri. :-)
PhiLho
Catatan: Jawaban JSON.stringify () tampaknya cukup berguna, meskipun itu tidak diterima sebagai jawaban 'the'.
GuruM
Anda bisa mendapatkan output visual dan intuitif dari objek menggunakan nodedump: github.com/ragamufin/nodedump
ragamufin
Lihatlah di sana: stackoverflow.com/questions/4810841/…
monkeythedev

Jawaban:

31

Saya menulis sebuah fungsi untuk membuang objek JS dalam bentuk yang dapat dibaca, meskipun hasilnya tidak menjorok, tetapi seharusnya tidak terlalu sulit untuk menambahkan bahwa: Saya membuat fungsi ini dari yang saya buat untuk Lua (yang jauh lebih kompleks ) yang menangani masalah indentasi ini.

Ini adalah versi "sederhana":

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

Saya akan melihat sedikit meningkatkannya.
Catatan 1: Untuk menggunakannya, lakukan od = DumpObject(something)dan gunakan od.dump. Berbelit-belit karena saya ingin nilai len juga (jumlah item) untuk tujuan lain. Itu sepele untuk membuat fungsi mengembalikan hanya string.
Catatan 2: itu tidak menangani loop dalam referensi.

EDIT

Saya membuat versi lekukan.

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

Pilih lekukan Anda di telepon dengan panggilan rekursif, dan Anda menahan gaya dengan mengganti saluran yang dikomentari setelah ini.

... Saya melihat Anda menyiapkan versi Anda sendiri, yang bagus. Pengunjung akan punya pilihan.

PhiLho
sumber
1
Saya suka;) Tidak dapat membuatnya berfungsi dengan baik, tetapi jika Anda tidak keberatan, saya akan mencuri konsep tanpa malu-malu dan menulis sendiri :)
Dan
2
Salah satu kekurangan pendekatan ini (dibandingkan dengan metode JSON.stringify yang disarankan Jason) adalah tidak menunjukkan array objek dengan benar. Ketika Anda memiliki sebuah array objek itu muncul sebagai [Obyek objek].
Ryan
@Ryan: Maksud Anda objek asli browser? Ya, melihat kembali kode saya, saya melihat saya menambahkan komentar: // Sayang sekali jika satu bidang adalah objek ... :-P OK untuk pengujian saya di sini ... Tidak masalah untuk membuang struktur buatan pengguna. Saya melihat ada alternatif di bawah ini, jika Anda membutuhkan sesuatu yang lebih kuat.
PhiLho
Saya tidak bisa menggunakan ini. Saya mendapatkan infinite loop ketika saya mencoba untuk membuang beberapa data json.
neoneye
1
@RaphaelDDL & PhiLho - Ukuran tumpukan panggilan maksimum juga dapat dipicu pada objek kecil; satu dengan referensi properti untuk dirinya sendiri. Referensi seperti itu akan menyebabkan loop tak terbatas dengan fungsi ini.
skibulk
233

Gunakan Crockford's JSON.stringify seperti ini:

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

Variabel textakan terlihat seperti ini:

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

Ngomong-ngomong, ini tidak membutuhkan lebih dari file JS - itu akan bekerja dengan perpustakaan apa pun, dll

Jason Bunting
sumber
5
Ini hampir pasti jawaban terbaik yang akan Anda dapatkan. Saya telah mengajar 4 atau 5 non-programmer untuk membaca dan mengedit struktur data JSON.stringified dan menggunakannya secara luas untuk file konfigurasi.
Joel Anair
1
Aneh bahwa itu akan menyebabkan masalah - itu memang memperkenalkan nama "JSON" ke namespace global, sehingga dapat menyebabkan masalah Anda. Periksa namespace Anda untuk "JSON" sebelum menambahkan ini untuk melihat apakah ada tabrakan.
Jason Bunting
1
Nah, prototipe itu jahat seperti itu ...;)
Jason Bunting
7
Pembaruan pada ini, dengan Firefox 3.5 dan di atasnya, JSON.stringify adalah bawaan. ( developer.mozilla.org/En/Using_JSON_in_Firefox ), jadi jika Anda hanya mencoba melihat objek JSON untuk keperluan debugging, Anda dapat melakukannya tanpa ketergantungan JS tambahan.
Greg Bernhardt
3
Juga di Chrome. Namun, JSON.stringify gagal pada data sirkuler JSON.stringify((function(){var x = []; x.push(x); return x})())dan banyak jenis objek lainnya JSON.stringify(/foo/).
Kragen Javier Sitaker
21

Anda dapat menggunakan yang berikut ini

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

Di Firebug, jika Anda baru saja console.debug ("%o", my_object)dapat mengkliknya di konsol dan masukkan penjelajah objek interaktif. Ini menunjukkan seluruh objek, dan memungkinkan Anda memperluas objek bersarang.

John Millikin
sumber
1
Masalah dengan itu adalah hanya menunjukkan objek 'paling atas' - saya punya puluhan objek bersarang, dan saya benar-benar harus dapat melihat seluruh konten sekaligus, dan yang penting, melihat di mana hal-hal berubah. Jadi Firebug benar-benar tidak bekerja untuk saya dalam kasus ini.
Dan
(ya saya tahu Anda dapat mengklik untuk memperluasnya, tetapi mengklik 10 atau lebih tautan setiap kali saya ingin membuang data adalah apa yang saya lakukan sekarang - kemajuan yang sangat lambat)
Dan
1
Ini juga berfungsi di Chrome (dan karena itu mungkin di Safari).
Kragen Javier Sitaker
9

Bagi mereka yang mencari cara luar biasa untuk melihat objek Anda, periksa prettyPrint.js

Membuat tabel dengan opsi tampilan yang dapat dikonfigurasi untuk dicetak di suatu tempat di dokumen Anda. Lebih baik dilihat daripada di console.

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

masukkan deskripsi gambar di sini

RaphaelDDL
sumber
6

Saya sedang pemrograman Rhinodan saya tidak puas dengan jawaban yang diposting di sini. Jadi saya sudah menulis printer cantik saya sendiri:

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

Outputnya terlihat seperti ini:

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

Saya juga mempostingnya sebagai Intisari untuk perubahan apa pun di masa depan yang mungkin diperlukan.

pengetahuan
sumber
7
Mungkin ini adalah printer yang cantik tetapi kode sebenarnya tidak terlihat sangat cantik :)
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')
])

menjadi

[
   [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 (Kerangka kerja pengujian unit yang digunakan oleh jQuery) menggunakan versi jsDump yang sedikit ditambal.


JSON.stringify () bukan pilihan terbaik pada beberapa kasus.

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

Mengambil pimpinan PhiLho (terima kasih banyak :)), saya akhirnya menulis sendiri karena saya tidak bisa membuatnya melakukan apa yang saya inginkan. Ini cukup kasar dan siap, tetapi itu pekerjaan yang saya butuhkan. Terima kasih atas saran yang luar biasa.

Saya tahu itu bukan kode yang brilian, tetapi untuk apa nilainya, ini dia. Seseorang mungkin menganggapnya berguna:

// 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
sumber
1
Ngomong-ngomong, meskipun kamu bisa, kamu tidak boleh mengakhiri garis tanpa titik koma. Juga, cara standar untuk melakukan __ if (! Pad) pad = '' __ adalah: __ pad = (pad || '') __
Jason Bunting
Saya setuju jika (! Foo) foo = ... vs foo = (foo || ...), tapi apa alasan untuk mengakhiri semua baris dengan titik koma?
Dan
1
Anda akan mengalami beberapa keanehan yang tidak menyenangkan dari bahasa tersebut jika tidak, belum lagi Anda tidak akan dapat dengan mudah memperkecil kode Anda (kecuali jika minifier yang Anda gunakan cukup bagus untuk menempelkan titik koma di dalam Anda). Lihat stackoverflow.com/questions/42247 untuk lebih jelasnya.
Jason Bunting
1
if (! pad) pad = ''; lebih murah, lebih fleksibel & lebih mudah dibaca daripada pad = (pad || ''); meskipun dengan jumlah menit. Jika Anda bersikeras pada formulir itu, hapus tanda kurung asing. pad = pad || ''; 3 alasan untuk titik koma: JS otomatis menyisipkan titik koma garis akhir ketika melihat bahwa menghilangkannya akan menimbulkan kesalahan. 1) Ini memaksa sedikit lebih lambat daripada menambahkannya sendiri, dan 2) dapat menyebabkan kesalahan ketika baris berikutnya terjadi untuk tidak melempar kesalahan saat digabungkan. 3) akan mencegah kode Anda dikecilkan.
SamGoody
1

Ini benar-benar hanya sebuah komentar pada Jason Bunting "Use Crockford's JSON.stringify", tetapi saya tidak dapat menambahkan komentar pada jawaban itu.

Seperti disebutkan dalam komentar, JSON.stringify tidak cocok dengan pustaka Prototipe (www.prototypejs.org). Namun, cukup mudah untuk membuat mereka bermain bersama dengan baik untuk sementara waktu menghapus metode Array.prototype.toJSON yang ditambahkan prototipe, jalankan Crockford's strify (), lalu kembalikan seperti ini:

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

Saya pikir respons J. Buntings tentang penggunaan JSON.stringify juga bagus. Selain itu, Anda dapat menggunakan JSON.stringify melalui YUI objek JSON jika Anda menggunakan YUI. Dalam kasus saya, saya perlu membuang ke HTML sehingga lebih mudah untuk hanya men-tweak / memotong / menempel respon 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
sumber
1

Banyak orang menulis kode di utas ini, dengan banyak komentar tentang berbagai gotcha. Saya menyukai solusi ini karena sepertinya lengkap dan merupakan file tunggal tanpa ketergantungan.

browser

simpuljs

Ini bekerja "di luar kotak" dan memiliki kedua versi node dan browser (mungkin hanya pembungkus yang berbeda tetapi saya tidak menggali untuk mengkonfirmasi).

Perpustakaan juga mendukung pencetakan XML, SQL dan CSS, tapi saya belum mencoba fitur-fitur itu.

mm2001
sumber
0

Yang sederhana untuk mencetak elemen sebagai string:

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
sumber
0

Perpustakaan NeatJSON saya memiliki versi Ruby dan JavaScript . Ini tersedia secara bebas di bawah Lisensi MIT (permisif). Anda dapat melihat demo / konverter online di:
http://phrogz.net/JS/neatjson/neatjson.html

Beberapa fitur (semua opsional):

  • Bungkus dengan lebar tertentu; jika suatu objek atau array dapat ditampung di baris, itu disimpan pada satu baris.
  • Sejajarkan titik dua untuk semua kunci dalam suatu objek.
  • Sortir kunci ke objek berdasarkan abjad.
  • Memformat angka floating point ke jumlah desimal tertentu.
  • Saat membungkus, gunakan versi 'pendek' yang menempatkan tanda kurung buka / tutup untuk array dan objek pada baris yang sama dengan nilai pertama / terakhir.
  • Kontrol spasi putih untuk array dan objek secara granular (kurung di dalam, sebelum / sesudah titik dua dan koma).
  • Bekerja di browser web dan sebagai modul Node.js.
Phrogz
sumber
-5

flexjson menyertakan fungsi prettyPrint () yang mungkin memberi Anda apa yang Anda inginkan.

andy
sumber