การจัดรูปแบบข้อมูล JavaScript / เครื่องพิมพ์สวย


124

ฉันกำลังพยายามหาวิธีpretty printในโครงสร้างข้อมูล JavaScript ในรูปแบบที่มนุษย์อ่านได้สำหรับการดีบัก

ฉันมีโครงสร้างข้อมูลที่ค่อนข้างใหญ่และซับซ้อนถูกเก็บไว้ใน JS และฉันจำเป็นต้องเขียนโค้ดเพื่อจัดการกับมัน เพื่อที่จะทราบว่าฉันกำลังทำอะไรอยู่และฉันกำลังทำอะไรผิดสิ่งที่ฉันต้องการจริงๆคือต้องสามารถดูโครงสร้างข้อมูลได้อย่างครบถ้วนและอัปเดตเมื่อใดก็ตามที่ฉันทำการเปลี่ยนแปลงผ่าน UI

ข้อมูลทั้งหมดนี้ฉันจัดการได้ด้วยตัวเองนอกเหนือจากการหาวิธีที่ดีในการถ่ายโอนโครงสร้างข้อมูล JavaScript ไปยังสตริงที่มนุษย์อ่านได้ JSON จะทำได้ แต่จำเป็นต้องมีการจัดรูปแบบและเยื้องอย่างดี ฉันมักจะใช้สิ่งที่ทิ้ง DOM ที่ยอดเยี่ยมของ Firebug สำหรับสิ่งนี้ แต่ฉันจำเป็นต้องสามารถเห็นโครงสร้างทั้งหมดได้ในคราวเดียวซึ่งดูเหมือนจะเป็นไปไม่ได้ใน Firebug

ข้อเสนอแนะใด ๆ ยินดีต้อนรับ

ขอบคุณล่วงหน้า.


ไม่แน่ใจว่าคุณได้รับแจ้งการแก้ไขคำตอบหรือไม่ ดังนั้นฉันจึงเขียนความคิดเห็นนี้เพื่อแจ้งให้คุณทราบว่าฉันได้เพิ่มเวอร์ชันของการถ่ายโอนข้อมูลแบบเยื้องของฉันเอง :-)
PhiLho

หมายเหตุ: คำตอบ JSON.stringify () ดูเหมือนจะมีประโยชน์มากแม้ว่าจะไม่ได้รับการยอมรับว่าเป็นคำตอบ 'the'
GuruM

คุณสามารถรับผลลัพธ์ที่เป็นภาพและใช้งานง่ายของวัตถุโดยใช้ nodedump: github.com/ragamufin/nodedump
ragamufin

คำตอบ:


31

ฉันเขียนฟังก์ชันเพื่อถ่ายโอนออบเจ็กต์ JS ในรูปแบบที่อ่านได้แม้ว่าเอาต์พุตจะไม่เยื้อง แต่ก็ไม่ควรเพิ่มสิ่งนั้นยากเกินไป: ฉันสร้างฟังก์ชันนี้จากสิ่งที่ฉันสร้างขึ้นสำหรับ Lua (ซึ่งซับซ้อนกว่ามาก ) ซึ่งจัดการปัญหาการเยื้องนี้

นี่คือเวอร์ชัน "ธรรมดา":

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

ฉันจะดูที่การปรับปรุงมันเล็กน้อย
หมายเหตุ 1: หากต้องการใช้ให้ทำod = DumpObject(something)และใช้ od.dump สับสนเพราะฉันต้องการค่า len ด้วย (จำนวนรายการ) เพื่อจุดประสงค์อื่น เป็นเรื่องเล็กน้อยที่จะทำให้ฟังก์ชันส่งคืนเฉพาะสตริง
หมายเหตุ 2: ไม่จัดการลูปในการอ้างอิง

แก้ไข

ฉันทำเวอร์ชันเยื้อง

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

เลือกการเยื้องของคุณในบรรทัดด้วยการเรียกซ้ำและคุณรั้งสไตล์โดยการสลับบรรทัดที่แสดงความคิดเห็นหลังจากนี้

... ฉันเห็นคุณเขียนเวอร์ชั่นของคุณเองซึ่งเป็นสิ่งที่ดี ผู้เยี่ยมชมจะมีทางเลือก


1
ฉันชอบ;) ไม่สามารถทำให้มันทำงานได้อย่างถูกต้อง แต่ถ้าคุณไม่รังเกียจฉันจะขโมยแนวคิดไปอย่างไร้ยางอายและเขียนของตัวเอง :)
Dan

2
แนวทางสั้น ๆ อย่างหนึ่งของแนวทางนี้ (เมื่อเทียบกับวิธี JSON.stringify ที่เจสันแนะนำ) ก็คือมันไม่ได้แสดงอาร์เรย์ของวัตถุอย่างถูกต้อง เมื่อคุณมีอาร์เรย์ของวัตถุจะแสดงเป็น [object Object]
Ryan

@Ryan: คุณหมายถึงวัตถุพื้นเมืองของเบราว์เซอร์? ใช่เมื่อมองย้อนกลับไปที่รหัสของฉันฉันเห็นว่าฉันได้เพิ่มความคิดเห็น: // แย่มากถ้าฟิลด์หนึ่งเป็นวัตถุ ... :-P ตกลงสำหรับการทดสอบของฉันที่นี่ ... สามารถถ่ายโอนโครงสร้างที่ผู้ใช้สร้างขึ้นได้ ฉันเห็นว่ามีทางเลือกอื่นด้านล่างหากคุณต้องการสิ่งที่แข็งแกร่งกว่านี้
ฟีลโฮ

ฉันไม่สามารถใช้สิ่งนี้ได้ ฉันได้รับการวนซ้ำที่ไม่มีที่สิ้นสุดเมื่อพยายามถ่ายโอนข้อมูล json บางส่วน
neoneye

1
@RaphaelDDL & PhiLho - ขนาดสแต็กการโทรสูงสุดสามารถเรียกใช้บนวัตถุขนาดเล็กได้ หนึ่งที่มีการอ้างอิงคุณสมบัติถึงตัวมันเอง การอ้างอิงดังกล่าวจะทำให้เกิดการวนซ้ำแบบไม่สิ้นสุดด้วยฟังก์ชันนี้
skibulk

233

ใช้JSON.stringify ของ Crockfordดังนี้:

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

ตัวแปรtextจะมีลักษณะดังนี้:

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

อย่างไรก็ตามสิ่งนี้ไม่ต้องการอะไรมากไปกว่าไฟล์ JS - มันจะทำงานกับไลบรารีใด ๆ ฯลฯ


5
นี่เป็นคำตอบที่ดีที่สุดที่คุณจะได้รับ ฉันได้สอนผู้ที่ไม่ใช่โปรแกรมเมอร์ 4 หรือ 5 คนให้อ่านและแก้ไขโครงสร้างข้อมูล JSON.stringified และใช้อย่างกว้างขวางสำหรับไฟล์คอนฟิกูเรชัน
Joel Anair

1
แปลกที่มันจะทำให้เกิดปัญหา - มันแนะนำชื่อ "JSON" ให้กับเนมสเปซส่วนกลางซึ่งอาจทำให้คุณเกิดปัญหาได้ ตรวจสอบเนมสเปซของคุณสำหรับ "JSON" ก่อนเพิ่มเพื่อดูว่ามีการชนกันหรือไม่
Jason Bunting

1
ดีต้นแบบก็ชั่วอย่างนั้น ... ;)
Jason Bunting

7
การอัปเดตเกี่ยวกับสิ่งนี้ใน Firefox 3.5 ขึ้นไป JSON.stringify มีอยู่ในตัว ( developer.mozilla.org/En/Using_JSON_in_Firefox ) ดังนั้นหากคุณแค่พยายามดูออบเจ็กต์ JSON เพื่อวัตถุประสงค์ในการดีบักคุณสามารถทำได้โดยไม่ต้องพึ่งพา JS เพิ่มเติม
Greg Bernhardt

3
นอกจากนี้ใน Chrome แต่ล้มเหลวใน JSON.stringify ข้อมูลกลมJSON.stringify((function(){var x = []; x.push(x); return x})())และชนิดอื่น ๆ JSON.stringify(/foo/)ของวัตถุ
Kragen Javier Sitaker

21

คุณสามารถใช้สิ่งต่อไปนี้

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

15

ในFirebugถ้าคุณเพียงแค่console.debug ("%o", my_object)คลิกที่มันในคอนโซลและเข้าสู่ตัวสำรวจวัตถุแบบโต้ตอบ แสดงวัตถุทั้งหมดและช่วยให้คุณขยายวัตถุที่ซ้อนกัน


1
ปัญหาคือมันแสดงเฉพาะวัตถุ 'บนสุด' เท่านั้น - ฉันมีวัตถุซ้อนกันหลายสิบชิ้นและฉันต้องสามารถดูเนื้อหาทั้งหมดได้ในคราวเดียวและที่สำคัญคือดูว่าสิ่งต่างๆกำลังเปลี่ยนแปลงไปที่ไหน ดังนั้น Firebug ไม่ได้ผลสำหรับฉันในกรณีนี้
แดน

(ใช่ฉันรู้ว่าคุณสามารถคลิกเพื่อขยายได้ แต่การคลิก 10 ลิงก์หรือมากกว่านั้นทุกครั้งที่ฉันต้องการถ่ายโอนข้อมูลคือสิ่งที่ฉันกำลังทำอยู่ตอนนี้ความคืบหน้าช้ามาก)
Dan

1
สิ่งนี้ยังใช้งานได้ใน Chrome (ดังนั้นจึงน่าจะอยู่ใน Safari)
Kragen Javier Sitaker


9

สำหรับผู้ที่มองหาวิธีที่ยอดเยี่ยมในการดูวัตถุของคุณให้ตรวจสอบ prettyPrint.js

สร้างตารางที่มีตัวเลือกมุมมองที่กำหนดค่าได้เพื่อพิมพ์ที่ใดที่หนึ่งในเอกสารของคุณ ดูดีกว่าในไฟล์console.

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

ใส่คำอธิบายภาพที่นี่


6

ฉันกำลังเขียนโปรแกรมRhinoและไม่พอใจกับคำตอบใด ๆ ที่โพสต์ไว้ที่นี่ ฉันจึงเขียนเครื่องพิมพ์สวย ๆ ของตัวเอง:

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

ผลลัพธ์มีลักษณะดังนี้:

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

ฉันยังโพสต์ไว้เป็นส่วนสำคัญที่นี่สำหรับการเปลี่ยนแปลงในอนาคตที่อาจจำเป็น


7
มันอาจจะเป็นเครื่องพิมพ์ที่สวย แต่โค้ดก็ดูไม่สวยเท่าไหร่ :)
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')
])

กลายเป็น

[
   [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 (เฟรมเวิร์กการทดสอบหน่วยที่ใช้โดย jQuery) โดยใช้ jsDump เวอร์ชันแพตช์เล็กน้อย


JSON.stringify () ไม่ใช่ตัวเลือกที่ดีที่สุดในบางกรณี

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

2

รับบทนำของฟีลโฮ (ขอบคุณมาก :)) จบลงด้วยการเขียนของตัวเองเพราะไม่สามารถให้เขาทำในสิ่งที่ต้องการได้ ค่อนข้างหยาบและพร้อม แต่งานที่ฉันต้องการ ขอบคุณทุกคำแนะนำที่ดีเยี่ยม

ไม่ใช่รหัสที่ยอดเยี่ยมฉันรู้ แต่สำหรับสิ่งที่คุ้มค่านี่คือสิ่งที่ อาจมีคนพบว่ามีประโยชน์:

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

1
อย่างไรก็ตามแม้ว่าคุณจะทำได้ แต่ก็ไม่ควรจบบรรทัดโดยไม่มีอัฒภาค นอกจากนี้วิธีมาตรฐานในการทำ __ if (! pad) pad = '' __ จะเป็น: __ pad = (pad || '') __
Jason Bunting

ฉันใช้ประเด็นของคุณเกี่ยวกับ if (! foo) foo = ... vs foo = (foo || ... ) แต่เหตุผลในการลงท้ายทุกบรรทัดด้วยอัฒภาคคืออะไร?
แดน

1
คุณจะพบกับความแปลกประหลาดที่น่ารังเกียจของภาษาหากคุณไม่ได้ไม่ต้องพูดถึงคุณจะไม่สามารถย่อขนาดโค้ดของคุณได้อย่างง่ายดาย (เว้นแต่ตัวย่อที่คุณใช้จะดีพอที่จะติดอัฒภาคให้คุณ) ดูstackoverflow.com/questions/42247สำหรับรายละเอียดเพิ่มเติม
Jason Bunting

1
ถ้า (! pad) pad = ''; มีราคาถูกกว่ายืดหยุ่นกว่าและอ่านได้ง่ายกว่า pad = (pad || ''); แม้ว่าจะคิดเป็นนาทีก็ตาม หากคุณยืนยันในแบบฟอร์มนั้นให้ลบวงเล็บที่ไม่เกี่ยวข้องออก pad = แผ่น || ''; 3 เหตุผลสำหรับอัฒภาค: JS แทรกอัฒภาคท้ายบรรทัดอัตโนมัติเมื่อเห็นว่าการละเว้นจะทำให้เกิดข้อผิดพลาด 1) นี่เป็นการบังคับให้เล็กลงเล็กน้อยช้ากว่าการเพิ่มด้วยตัวเองและ 2) อาจทำให้เกิดข้อผิดพลาดเมื่อบรรทัดถัดไปเกิดขึ้นเพื่อไม่ให้เกิดข้อผิดพลาดเมื่อรวมกัน 3) จะป้องกันไม่ให้รหัสของคุณลดขนาดลง
SamGoody

1

นี่เป็นเพียงความคิดเห็นใน "Use Crockford's JSON.stringify" ของ Jason Bunting แต่ฉันไม่สามารถเพิ่มความคิดเห็นในคำตอบนั้นได้

ตามที่ระบุไว้ในความคิดเห็น JSON.stringify เล่นได้ไม่ดีกับไลบรารี Prototype (www.prototypejs.org) อย่างไรก็ตามมันค่อนข้างง่ายที่จะทำให้พวกเขาเล่นด้วยกันได้ดีโดยการลบเมธอด Array.prototype.toJSON ชั่วคราวที่ต้นแบบเพิ่มเรียกใช้ stringify () ของ Crockford จากนั้นใส่กลับเช่นนี้:

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

1

ฉันคิดว่าการตอบสนองของ J. Buntings เกี่ยวกับการใช้ JSON.stringify นั้นดีเช่นกัน นอกจากนี้คุณสามารถใช้ JSON.stringify ผ่านวัตถุ YUIs JSON หากคุณใช้ YUI ในกรณีของฉันฉันต้องถ่ายโอนข้อมูลไปยัง HTML เพื่อให้ง่ายต่อการปรับแต่ง / ตัด / วางการตอบสนองของ 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;
}

1

มีคนเขียนโค้ดในกระทู้นี้มากมายพร้อมความคิดเห็นมากมายเกี่ยวกับ gotcha ต่างๆ ฉันชอบโซลูชันนี้เพราะดูเหมือนจะสมบูรณ์และเป็นไฟล์เดียวที่ไม่มีการอ้างอิง

เบราว์เซอร์

nodejs

มันใช้งานได้ "นอกกรอบ" และมีทั้งเวอร์ชันโหนดและเบราว์เซอร์ (น่าจะเป็นเพียง Wrapper ที่แตกต่างกัน แต่ฉันไม่ได้ขุดเพื่อยืนยัน)

ไลบรารียังรองรับการพิมพ์ XML, SQL และ CSS ที่สวยงาม แต่ฉันยังไม่ได้ลองใช้คุณสมบัติเหล่านั้น


0

วิธีง่ายๆสำหรับการพิมพ์องค์ประกอบเป็นสตริง:

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

0

ฉันNeatJSONห้องสมุดมีทั้งทับทิมและJavaScript รุ่น สามารถใช้ได้อย่างอิสระภายใต้ใบอนุญาต MIT (อนุญาต) คุณสามารถดูการสาธิต / ตัวแปลงออนไลน์ได้ที่:
http://phrogz.net/JS/neatjson/neatjson.html

คุณสมบัติบางอย่าง (เป็นทางเลือกทั้งหมด):

  • ตัดให้มีความกว้างเฉพาะ ถ้าออบเจ็กต์หรืออาร์เรย์สามารถใส่ลงในบรรทัดได้ก็จะเก็บไว้ในบรรทัดเดียว
  • จัดตำแหน่งเครื่องหมายทวิภาคสำหรับคีย์ทั้งหมดในวัตถุ
  • เรียงคีย์ไปยังวัตถุตามตัวอักษร
  • จัดรูปแบบตัวเลขทศนิยมเป็นจำนวนทศนิยมที่ระบุ
  • เมื่อทำการตัดให้ใช้เวอร์ชัน 'สั้น' ที่วางวงเล็บเปิด / ปิดสำหรับอาร์เรย์และวัตถุในบรรทัดเดียวกับค่าแรก / ค่าสุดท้าย
  • ควบคุมช่องว่างสำหรับอาร์เรย์และวัตถุในลักษณะที่ละเอียด (ภายในวงเล็บก่อน / หลังเครื่องหมายทวิภาคและเครื่องหมายจุลภาค)
  • ทำงานในเว็บเบราว์เซอร์และเป็นโมดูล Node.js

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.