Форматування даних JavaScript / гарний принтер


124

Я намагаюся знайти шлях до pretty printструктури даних JavaScript у читаній людиною формі для налагодження.

У мене досить велика і складна структура даних зберігається в JS, і мені потрібно написати якийсь код, щоб маніпулювати нею. Для того, щоб розробити те, що я роблю, і де я помиляюся, мені дійсно потрібно, щоб я могла бачити структуру даних у повному обсязі та оновлювати її щоразу, коли я вношу зміни через інтерфейс користувача.

З усіма цими речами я можу впоратися самостійно, окрім того, як знайти приємний спосіб скинути структуру даних JavaScript до людського читаного рядка. JSON міг би зробити, але це дійсно потрібно добре відформатувати та відкласти. Зазвичай я використовую для цього відмінний DOM-матеріал для демпінгу Firebug, але мені дійсно потрібно мати можливість бачити всю структуру одразу, що, здається, не можливо в Firebug.

Будь-які пропозиції вітаються.

Заздалегідь спасибі.


Не впевнений, чи отримують ви повідомлення про редагування відповідей. Тому я пишу цей коментар, щоб повідомити вам, що я додав власну версію з відступом. :-)
PhiLho

Примітка: відповідь JSON.stringify () здається досить корисною, хоча вона не приймається як "відповідь".
ГуруМ

Ви можете отримати візуальний та інтуїтивний вихід об'єктів за допомогою 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: він не обробляє петлі в посиланнях.

EDIT

Я зробив відступну версію.

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
Мені подобається;) Я не можу змусити його працювати належним чином, але якщо ви не заперечуєте, я збираюся безсоромно вкрасти концепцію і написати своє :)
День,

2
Одним із коротких варіантів такого підходу (порівняно з методом JSON.stringify, який пропонує Джейсон) є те, що він не відображає масиви об'єктів належним чином. Якщо у вас є масив об'єктів, він відображається як [object Object].
Райан

@Ryan: Ви маєте на увазі рідні об’єкти браузера? Так, оглянувшись на свій код, я побачив, що додав коментар: // Дуже погано, якщо одне поле є об’єктом ... :-P ОК для мого тестування тут ... Добре скинути створені користувачем структури. Я бачу, що нижче є альтернативи, якщо вам потрібно щось більш надійне.
PhiLho

Я не можу цим скористатися. Я отримую нескінченний цикл, коли намагаюся скинути деякі дані json.
neoneye

1
@RaphaelDDL & PhiLho - максимальний розмір стека викликів також може бути запущений на невеликому об'єкті; той, який має посилання на властивість до себе. Таке посилання спричинило б нескінченний цикл з цією функцією.
skibulk

233

Використовуйте Crockford's JSON.stringify так:

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 та широко використовувати їх для файлів конфігурації.
Джоель Анаір

1
Дивно, що це може спричинити проблеми - воно вводить назву "JSON" у глобальний простір імен, так що це може викликати у вас проблеми. Перевірте, чи є у вашому просторі імен "JSON", перш ніж додавати його, щоб побачити, чи існує зіткнення.
Джейсон Бантінг

1
Що ж, прототип такий злий ...;)
Джейсон Бантінг

7
Оновлення щодо цього, з Firefox 3.5 і вище, вбудований JSON.stringify. ( developer.mozilla.org/En/Using_JSON_in_Firefox ), тому якщо ви просто намагаєтесь побачити JSON-об’єкт для цілей налагодження, ви можете це зробити без зайвих залежностей JS.
Грег Бернхардт

3
Також у Chrome. Однак JSON.stringify не вдається на кругових даних JSON.stringify((function(){var x = []; x.push(x); return x})())та на багатьох інших видах об'єктів JSON.stringify(/foo/).
Краген Хав'єр Сітакер

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).
Краген Хав'єр Сітакер


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 (Unit-testing Framework, використовуваний jQuery), використовуючи злегка виправлену версію jsDump.


JSON.stringify () - не найкращий вибір у деяких випадках.

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

2

Взявши на себе керівництво PhiLho (велике спасибі :)), я закінчив писати своє, оскільки я не міг змусити його зробити те, що я хотів. Це досить грубо і готово, але це робить ту роботу, яка мені потрібна. Дякую всім за чудові пропозиції.

Я не знаю, це геніальний код, але для чого воно варте, ось воно і є. Хтось може вважати його корисним:

// 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
До речі, навіть якщо ви можете, ви не повинні закінчувати рядки без крапки з комою. Також стандартним способом виконання __ якщо (! Pad) pad = '' __ буде: __ pad = (pad || '') __
Джейсон Бантінг,

Я вважаю, що якщо (! Foo) foo = ... vs foo = (foo || ...), але яка обгрунтування закінчення всіх рядків крапками з комою?
День

1
Якщо ви цього не зробите, ви зіткнетесь з якимись неприємними ідіосинкразіями мови, не кажучи вже про те, що ви не зможете легко мінімізувати свій код (якщо тільки мініфікатор, який ви використовуєте, досить приємний, щоб вставити крапки з комою для вас). Дивіться stackoverflow.com/questions/42247 для отримання більш детальної інформації.
Джейсон Бантінг

1
if (! pad) pad = ''; дешевше, гнучкіше і читабельніше, ніж pad = (pad || ''); хоч на хвилинну суму. Якщо ви наполягаєте на цій формі, видаліть сторонні дужки. колодка = колодка || ''; 3 причини крапки з комою: JS автоматично вставляє крапки з комою в кінці, коли бачить, що їх пропускання призведе до помилки. 1) Це виконує підлітковий біт повільніше, ніж додавати його самостійно, і 2) може призвести до помилок, коли наступний рядок не стане помилкою при поєднанні. 3) запобіжить мінімізації вашого коду.
SamGoody

1

Це дійсно лише коментар до "Використовувати JSON.stringify" Крокфорда Джейсона Бантінга, але я не зміг додати коментар до цієї відповіді.

Як зазначається в коментарях, JSON.stringify не грає добре з бібліотекою Prototype (www.prototypejs.org). Однак змусити їх добре грати разом, тимчасово видаливши метод Array.prototype.toJSON, який додає прототип, досить легко, запустити Crockford's stringify (), а потім повернути його так:

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

1

Я вважав, що реакція Дж. Бантінгса щодо використання JSON.stringify також була хорошою. Окрім того, ви можете використовувати JSON.stringify через об’єкт JSI 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

Багато людей написали код у цій темі, з багатьма коментарями про різні ґетчі. Це рішення мені сподобалось, оскільки воно здавалося повним і являло собою єдиний файл без залежностей.

браузер

nodejs

Він працював "поза коробкою" і має версії для вузла та браузера (імовірно, різні обгортки, але я не намагався підтвердити).

Бібліотека також підтримує друк 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 має версії Ruby та JavaScript . Він вільно доступний за ліцензією (дозвільною) MIT. Переглянути онлайн-демонстрацію / конвертер можна за посиланням:
http://phrogz.net/JS/neatjson/neatjson.html

Деякі функції (усі необов’язково):

  • Загорнути на певну ширину; якщо об'єкт або масив може поміститися на лінії, він зберігається на одній лінії.
  • Вирівняйте колонки для всіх клавіш об'єкта.
  • Сортуйте ключі до об'єкта за алфавітом.
  • Відформатуйте числа з плаваючою комою до певної кількості десяткових знаків.
  • Під час обгортання використовуйте "коротку" версію, яка встановлює дужки відкритих / закритих для масивів та об'єктів у тому ж рядку, що і перше / останнє значення.
  • Контролюйте пробільний масив для масивів та об'єктів детально (всередині дужок, перед / після колонок та коми).
  • Працює у веб-браузері і як модуль Node.js.

-5

flexjson включає в себе функцію prettyPrint (), яка може дати вам те, що ви хочете.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.