Định dạng dữ liệu JavaScript / máy in đẹp


124

Tôi đang cố gắng tìm cách pretty printcấu trúc dữ liệu JavaScript ở dạng dễ đọc để gỡ lỗi.

Tôi có một cấu trúc dữ liệu khá lớn và phức tạp đang được lưu trữ trong JS và tôi cần phải viết một số mã để thao tác nó. Để tìm ra những gì tôi đang làm và sai ở đâu, điều tôi thực sự cần là có thể nhìn thấy toàn bộ cấu trúc dữ liệu và cập nhật nó bất cứ khi nào tôi thực hiện thay đổi thông qua UI.

Tất cả những thứ này tôi có thể tự xử lý, ngoài việc tìm ra một cách hay để kết cấu cấu trúc dữ liệu JavaScript thành một chuỗi có thể đọc được. JSON sẽ làm được, nhưng nó thực sự cần được định dạng độc đáo và thụt lề. Tôi thường sử dụng công cụ bán phá giá DOM tuyệt vời của Fireorms cho việc này, nhưng tôi thực sự cần phải có thể nhìn thấy toàn bộ cấu trúc cùng một lúc, điều này dường như không thể thực hiện được trong Fireorms.

Mọi góp ý đều được chào đón.

Cảm ơn trước.


Không chắc chắn nếu bạn được thông báo về các chỉnh sửa của câu trả lời. Vì vậy, tôi viết bình luận này để thông báo cho bạn rằng tôi đã thêm phiên bản bãi rác thụt lề của riêng mình. :-)
PhiLho

Lưu ý: Câu trả lời JSON.opesify () dường như khá hữu ích, mặc dù nó không được chấp nhận là 'câu trả lời'.
Giáo sư

Bạn có thể nhận được một đầu ra trực quan và trực quan của các đối tượng bằng cách sử dụng gật đầu: github.com/ragamufin/nodingump
ragamufin

Câu trả lời:


31

Tôi đã viết một hàm để kết xuất một đối tượng JS ở dạng có thể đọc được, mặc dù đầu ra không được thụt vào, nhưng không quá khó để thêm vào đó: Tôi đã tạo hàm này từ một hàm tôi tạo cho Lua (phức tạp hơn nhiều ) đã xử lý vấn đề thụt đầu dòng này.

Đây là phiên bản "đơn giản":

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

Tôi sẽ xem xét cải thiện nó một chút.
Lưu ý 1: Để sử dụng nó, hãy làm od = DumpObject(something)và sử dụng od.dump. Kết luận vì tôi cũng muốn giá trị len (số lượng vật phẩm) cho mục đích khác. Nó là tầm thường để làm cho hàm chỉ trả về chuỗi.
Lưu ý 2: nó không xử lý các vòng lặp trong tài liệu tham khảo.

BIÊN TẬP

Tôi đã thực hiện phiên bản thụt lề.

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

Chọn thụt lề của bạn trên đường dây với cuộc gọi đệ quy và bạn tạo kiểu kết nối bằng cách chuyển dòng nhận xét sau cuộc gọi này.

... Tôi thấy bạn đã đánh lên phiên bản của chính mình, điều đó thật tốt. Du khách sẽ có một sự lựa chọn.


1
Tôi thích;) Không thể làm cho nó hoạt động đúng, nhưng nếu bạn không phiền, tôi sẽ xấu hổ ăn cắp khái niệm và tự viết :)
Dan

2
Một cách tiếp cận ngắn của phương pháp này (so với phương thức JSON.opesify mà Jason gợi ý) là nó không hiển thị các mảng đối tượng đúng cách. Khi bạn có một mảng các đối tượng, nó sẽ hiển thị dưới dạng [Object Object].
Ryan

@Ryan: Ý bạn là các đối tượng bản địa của trình duyệt? Có, nhìn lại mã của tôi, tôi thấy tôi đã thêm một nhận xét: // Thật tệ nếu một trường là một đối tượng ... :-P OK cho thử nghiệm của tôi ở đây ... Không thể bỏ kết cấu do người dùng tạo. Tôi thấy có những lựa chọn thay thế dưới đây, nếu bạn cần một cái gì đó mạnh mẽ hơn.
PhiLho

Tôi không thể sử dụng cái này. Tôi nhận được vòng lặp vô hạn khi tôi cố gắng kết xuất một số dữ liệu json.
neoneye

1
@RaphaelDDL & PhiLho - Kích thước ngăn xếp cuộc gọi tối đa cũng có thể được kích hoạt trên một đối tượng nhỏ; một với một tài sản tham khảo cho chính nó. Một tham chiếu như vậy sẽ gây ra một vòng lặp vô hạn với chức năng này.
skibulk

233

Sử dụng JSON.opesify của Crockford như thế này:

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

Biến textsẽ trông như thế này:

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

Nhân tiện, điều này không đòi hỏi gì hơn tệp JS đó - nó sẽ hoạt động với bất kỳ thư viện nào, v.v.


5
Đây gần như chắc chắn là câu trả lời tốt nhất bạn sẽ nhận được. Tôi đã dạy 4 hoặc 5 người không lập trình viên đọc và chỉnh sửa cấu trúc dữ liệu JSON.opesified và sử dụng chúng rộng rãi cho các tệp cấu hình.
Joel Anair

1
Điều kỳ lạ là nó sẽ gây ra vấn đề - nó giới thiệu tên "JSON" cho không gian tên toàn cầu, do đó có thể gây ra sự cố cho bạn. Kiểm tra không gian tên của bạn cho "JSON" trước khi thêm phần này để xem có xung đột tồn tại không.
Jason Bunting

1
Chà, nguyên mẫu là xấu xa như thế ...;)
Jason Bunting

7
Một bản cập nhật về điều này, với Firefox 3.5 trở lên, JSON.opesify được tích hợp sẵn. ( developer.mozilla.org/En/Using_JSON_in_Firefox ), vì vậy nếu bạn chỉ đang cố gắng xem một đối tượng JSON cho mục đích gỡ lỗi, bạn có thể làm điều đó mà không cần phụ thuộc vào JS.
Greg Bernhardt

3
Cũng trong Chrome. Tuy nhiên, JSON.opesify không thành công trên dữ liệu vòng tròn JSON.stringify((function(){var x = []; x.push(x); return x})())và trên nhiều loại đối tượng khác JSON.stringify(/foo/).
Kragen Javier Sitaker

21

Bạn có thể sử dụng như sau

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

15

Trong Firebug, nếu bạn chỉ cần console.debug ("%o", my_object)bạn có thể nhấp vào nó trong bảng điều khiển và nhập một trình thám hiểm đối tượng tương tác. Nó hiển thị toàn bộ đối tượng và cho phép bạn mở rộng các đối tượng lồng nhau.


1
Vấn đề với nó là nó chỉ hiển thị đối tượng 'trên cùng' - tôi đã có hàng tá đối tượng lồng nhau và tôi thực sự cần phải có thể xem toàn bộ nội dung cùng một lúc và quan trọng là xem mọi thứ đang thay đổi ở đâu. Vì vậy, Fireorms thực sự không làm việc cho tôi trong trường hợp này.
Dan

(vâng, tôi biết bạn có thể nhấp để mở rộng chúng, nhưng nhấp vào 10 liên kết mỗi lần tôi muốn xóa dữ liệu là những gì tôi đang làm bây giờ - tiến độ rất chậm)
Dan

1
Điều này cũng hoạt động trong Chrome (và do đó có lẽ là trong Safari).
Kragen Javier Sitaker


9

Đối với những người đang tìm kiếm một cách tuyệt vời để xem đối tượng của bạn, hãy kiểm tra PrettyPrint.js

Tạo một bảng với các tùy chọn xem có thể định cấu hình sẽ được in ở đâu đó trên tài liệu của bạn. Nhìn tốt hơn trong console.

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

nhập mô tả hình ảnh ở đây


6

Tôi đang lập trình Rhinovà tôi không hài lòng với bất kỳ câu trả lời nào được đăng ở đây. Vì vậy, tôi đã viết máy in đẹp của riêng mình:

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

Đầu ra trông như thế này:

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

Tôi cũng đã đăng nó dưới dạng Gist ở đây cho bất kỳ thay đổi nào trong tương lai có thể được yêu cầu.


7
Nó có thể là một máy in đẹp nhưng mã không thực sự trông rất đẹp :)
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')
])

trở thành

[
   [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 (Khung kiểm thử đơn vị được sử dụng bởi jQuery) bằng cách sử dụng phiên bản jsDump được vá một chút.


JSON.opesify () không phải là lựa chọn tốt nhất trong một số trường hợp.

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

2

Lấy sự dẫn dắt của PhiLho (cảm ơn rất nhiều :)), cuối cùng tôi đã tự viết vì tôi không thể khiến anh ấy làm điều tôi muốn. Nó khá thô và sẵn sàng, nhưng đó là công việc tôi cần. Cảm ơn tất cả các bạn cho những gợi ý tuyệt vời.

Nó không phải là mã tuyệt vời, tôi biết, nhưng với giá trị của nó, nó ở đây. Ai đó có thể thấy nó hữu ích:

// 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
Nhân tiện, mặc dù bạn có thể, bạn không nên kết thúc dòng mà không có dấu chấm phẩy. Ngoài ra, cách làm tiêu chuẩn __ if (! Pad) pad = '' __ sẽ là: __ pad = (pad || '') __
Jason Bunting

Tôi nêu quan điểm của bạn về việc nếu (! Foo) foo = ... vs foo = (foo | | ...), nhưng lý do để kết thúc tất cả các dòng bằng dấu chấm phẩy là gì?
Dan

1
Bạn sẽ gặp phải một số đặc điểm khó chịu của ngôn ngữ nếu không, chưa kể bạn sẽ không thể dễ dàng thu nhỏ mã của mình (trừ khi công cụ khai thác bạn sử dụng đủ tốt để gắn dấu chấm phẩy cho bạn). Xem stackoverflow.com/questions/42247 để biết thêm chi tiết.
Jason Bunting

1
if (! pad) pad = ''; rẻ hơn, linh hoạt hơn và dễ đọc hơn pad = (pad || ''); mặc dù một lượng nhỏ Nếu bạn nhấn mạnh vào hình thức đó, loại bỏ dấu ngoặc đơn bên ngoài. pad = pad | | ''; 3 lý do cho dấu chấm phẩy: JS tự động chèn dấu chấm phẩy dòng cuối khi thấy rằng bỏ qua chúng sẽ gây ra lỗi. 1) Đây là một lực lượng chậm hơn một chút so với việc tự thêm nó và 2) có thể dẫn đến lỗi khi dòng tiếp theo xảy ra không gây ra lỗi khi kết hợp. 3) sẽ ngăn chặn mã của bạn bị thu nhỏ.
Samoody

1

Đây thực sự chỉ là một nhận xét về "Sử dụng JSON.opesify" của Jason Bunting, nhưng tôi không thể thêm nhận xét vào câu trả lời đó.

Như đã lưu ý trong các nhận xét, JSON.opesify không chơi tốt với thư viện Prototype (www.prototypejs.org). Tuy nhiên, khá dễ dàng để làm cho chúng chơi tốt với nhau bằng cách tạm thời xóa phương thức Array.prototype.toJSON mà nguyên mẫu thêm vào, chạy chuỗi của Crockford (), sau đó đưa nó trở lại như sau:

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

1

Tôi nghĩ rằng phản hồi của J. Buntings về việc sử dụng JSON.opesify cũng tốt. Bên cạnh đó, bạn có thể sử dụng JSON.opesify thông qua đối tượng JSON của YUI nếu bạn tình cờ sử dụng YUI. Trong trường hợp của tôi, tôi cần chuyển sang HTML để dễ dàng hơn trong việc điều chỉnh / cắt / dán phản hồi 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

Rất nhiều người viết mã trong chủ đề này, với nhiều ý kiến ​​về các vấn đề khác nhau. Tôi thích giải pháp này vì nó có vẻ hoàn chỉnh và là một tệp duy nhất không có phụ thuộc.

trình duyệt

nodejs

Nó hoạt động "vượt trội" và có cả phiên bản nút và trình duyệt (có lẽ chỉ là các trình bao bọc khác nhau nhưng tôi không đào để xác nhận).

Thư viện cũng hỗ trợ in XML, SQL và CSS đẹp, nhưng tôi chưa thử các tính năng đó.


0

Một đơn giản để in các phần tử dưới dạng chuỗi:

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

Thư viện NeatJSON của tôi có cả phiên bản Ruby và JavaScript . Nó được cung cấp miễn phí theo Giấy phép MIT (cho phép). Bạn có thể xem bản demo / trình chuyển đổi trực tuyến tại:
http://phrogz.net/JS/neatjson/neatjson.html

Một số tính năng (tất cả tùy chọn):

  • Bọc đến một chiều rộng cụ thể; nếu một đối tượng hoặc mảng có thể vừa trên dòng thì nó được giữ trên một dòng.
  • Căn chỉnh dấu hai chấm cho tất cả các khóa trong một đối tượng.
  • Sắp xếp các phím cho một đối tượng theo thứ tự abc.
  • Định dạng số dấu phẩy động thành một số thập phân cụ thể.
  • Khi gói, sử dụng phiên bản 'ngắn' đặt dấu ngoặc mở / đóng cho mảng và đối tượng trên cùng một dòng với giá trị đầu tiên / cuối cùng.
  • Kiểm soát khoảng trắng cho mảng và đối tượng theo cách chi tiết (bên trong ngoặc, trước / sau dấu hai chấm và dấu phẩy).
  • Hoạt động trong trình duyệt web và dưới dạng mô-đun Node.js.

-5

flexjson bao gồm một hàm beautifulPrint () có thể cung cấp cho bạn những gì bạn muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.