Я пытаюсь найти способ pretty print структуры данных JavaScript в удобочитаемой форме для отладки.
У меня довольно большая и сложная структура данных, хранящаяся в JS, и мне нужно написать код для управления ею. Чтобы понять, что я делаю и где ошибаюсь, мне действительно нужно иметь возможность видеть структуру данных во всей ее полноте и обновлять ее всякий раз, когда я вношу изменения через пользовательский интерфейс.
Со всем этим я могу справиться сам, не считая того, чтобы найти хороший способ сбросить структуру данных JavaScript в удобочитаемую строку. JSON подойдет, но он действительно должен быть хорошо отформатирован и с отступом. Я обычно использую для этого отличные средства дампа DOM от Firebug, но мне действительно нужно иметь возможность видеть всю структуру сразу, что, похоже, невозможно в Firebug.
Примечание: ответ JSON.stringify () кажется весьма полезным, хотя он не принимается как «ответ».
Вы можете получить визуальный и интуитивно понятный вывод объектов с помощью nodedump: github.com/ragamufin/nodedump
Взгляните туда: stackoverflow.com/questions/4810841/…



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В Firebug, если вы просто console.debug ("%o", my_object), вы можете щелкнуть по нему в консоли и войти в интерактивный проводник объектов. Он показывает весь объект и позволяет раскрывать вложенные объекты.
Проблема в том, что он показывает только «самый верхний» объект - у меня есть десятки вложенных объектов, и мне действительно нужно иметь возможность видеть все содержимое сразу, и, что важно, видеть, где что-то меняется. Так что Firebug в данном случае для меня не работает.
(да, я знаю, что вы можете щелкнуть, чтобы развернуть их, но щелкая около 10 ссылок каждый раз, когда я хочу сбросить данные, я делаю сейчас - очень медленный прогресс)
Это также работает в Chrome (и, следовательно, предположительно в Safari).
flexjson включает функцию prettyPrint (), которая может дать вам то, что вы хотите.
Используйте 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-файла - он будет работать с любой библиотекой и т. д.
Это почти наверняка лучший ответ, который вы получите. Я научил 4 или 5 непрограммистов читать и редактировать структуры данных JSON.stringified и широко использовать их для файлов конфигурации.
Да, очень хороший ответ, к сожалению, похоже, он не очень хорошо сочетается с чем-то еще в этом приложении (пока не знаю, что именно). Однако работает изолированно.
Странно, что это вызовет проблемы - он вводит имя «JSON» в глобальное пространство имен, так что это может вызвать у вас проблемы. Проверьте свое пространство имен на наличие "JSON" до, добавив это, чтобы увидеть, существует ли коллизия.
Да, проверил. Вероятно, это связано с библиотекой прототипов, поскольку она добавляет методы toJSON () ко многим вещам (не к Object, а ко всему остальному), что, похоже, вызовет проблемы.
Кроме того, возможно, вам следует использовать альтернативу, указав число вместо '\ t' в качестве последнего параметра ... дайте нам знать, что вы узнаете.
Он действительно конфликтует с прототипом toJSON (), который возвращает строку json, которую затем обрабатывает материал Дуга. Что, ну, неправильно :)
Ну, прототип такой злой ...;)
Обновление по этому поводу, с Firefox 3.5 и выше, JSON.stringify является встроенным. (developer.mozilla.org/En/Using_JSON_in_Firefox), поэтому, если вы просто пытаетесь увидеть объект JSON для целей отладки, вы можете сделать это без дополнительных зависимостей JS.
Также в Chrome. Однако JSON.stringify не работает с циклическими данными JSON.stringify((function(){var x = []; x.push(x); return x})()) и многими другими типами объектов JSON.stringify(/foo/).
Использование этого фрагмента кода работает в консоли Firefox FireBug, то есть console.info ('myObj', JSON.stringify (myObj, null, '\ t')); Однако, когда я пытаюсь скопировать вывод консоли в буфер обмена, я получаю однострочный вывод. Однако консоль Firebug показывает вывод JSON.stringify () с отступом. Есть идеи, почему это происходит?
Firebug, кажется, оборачивает вывод в <span>. Итак, чтобы скопировать текст с отступом, мне нужно: а) сначала сохранить вывод консоли как HTML, б) просмотреть исходный HTML-код и в) скопировать часть с отступом из элемента <span> источника HTML в буфер обмена. Уф !! Казалось бы, довольно много работы, чтобы просто скопировать структуру данных с отступом.
Я написал функцию для вывода 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$/, "");
}
Выберите отступ в строке с рекурсивным вызовом и закрепите стиль, переключив прокомментированную строку после этой.
... Я вижу, вы придумали свою версию, и это хорошо. У посетителей будет выбор.
Мне нравится;) Не могу заставить его работать должным образом, но если вы не возражаете, я без зазрения совести украду концепт и напишу свой :)
Одним из недостатков этого подхода (по сравнению с методом JSON.stringify, который предлагает Джейсон) является то, что он не отображает правильно массивы объектов. Когда у вас есть массив объектов, он отображается как [объект Object].
@Ryan: Вы имеете в виду собственные объекты браузера? Да, оглядываясь назад на свой код, я увидел, что добавил комментарий: // Плохо, если одно поле является объектом ... :-P Хорошо для моего теста здесь ... Можно сбрасывать структуры, созданные пользователем. Я вижу, что ниже есть альтернативы, если вам нужно что-то более надежное.
Я не могу это использовать. Я получаю бесконечный цикл, когда пытаюсь сбросить некоторые данные json.
В этой функции есть какой-то цикл, я не нашел где. Дает Uncaught RangeError: Maximum call stack size exceeded
@RaphaelDDL Это рекурсивная функция, она вызывает сама себя. Если вы используете его с огромным объектом, он действительно может превысить размер стека вызовов, хотя это маловероятно. Или, как neoneye, у вас может быть ссылка, выполняющая цикл в объекте (obj a ссылается на obj b, ссылаясь на obj a), что убивает такой алгоритм. Версия Lua обнаружила такой случай ценой дополнительной сложности.
@PhiLho Спасибо за ответ. К счастью, я нашел потрясающий дампер var, проверьте его: github.com/padolsey/prettyPrint.js Создайте таблицу со всем содержимым, настраиваемой глубиной и т.д. Протестировано на моем объекте, у которого достигнут размер стека, и он работал нормально.
Да, мой вариант очень упрощен, его легко включить в небольшой проект для получения быстрых результатов, но он ограничен. Есть и более прочные самосвалы, некоторые из них перечислены на этой странице ...
@RaphaelDDL & PhiLho - Максимальный размер стека вызовов также может быть активирован для небольшого объекта; один со ссылкой свойства на самого себя. Такая ссылка вызовет бесконечный цикл с этой функцией.
Взяв на себя инициативу 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
}
Кстати, даже если вы можете, вы не должны заканчивать строки без точки с запятой. Кроме того, стандартным способом выполнения __ if (! Pad) pad = '' __ будет: __ pad = (pad || '') __
Я понимаю вашу точку зрения на if (! Foo) foo = ... vs foo = (foo || ...), но каково основание для завершения всех строк точкой с запятой?
Если вы этого не сделаете, вы столкнетесь с некоторыми неприятными особенностями языка, не говоря уже о том, что вы не сможете легко минимизировать свой код (если только минификатор, который вы используете, не достаточно хорош, чтобы вставить точку с запятой). Подробнее см. stackoverflow.com/questions/42247.
если (! pad) pad = ''; дешевле, гибче и читабельнее, чем pad = (pad || ''); хотя и на минутную сумму. Если вы настаиваете на этой форме, удалите лишние скобки. pad = pad || ''; 3 причины использования точек с запятой: JS автоматически вставляет точки с запятой в конце строки, когда видит, что их пропуск вызовет ошибку. 1) Это принудительно немного медленнее, чем добавление самостоятельно, и 2) может привести к ошибкам, когда следующая строка не выдаст ошибку при объединении. 3) предотвратит минимизацию вашего кода.
На самом деле это просто комментарий Джейсона Бантинга «Использовать JSON.stringify Крокфорда», но я не смог добавить комментарий к этому ответу.
Как отмечено в комментариях, JSON.stringify не работает с библиотекой Prototype (www.prototypejs.org). Однако довольно легко заставить их хорошо взаимодействовать друг с другом, временно удалив метод Array.prototype.toJSON, добавленный прототипом, запустите Crockford stringify (), а затем верните его следующим образом:
var temp = Array.prototype.toJSON;
delete Array.prototype.toJSON;
$('result').value += JSON.stringify(profile_base, null, 2);
Array.prototype.toJSON = temp;
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
Я подумал, что ответ Дж. Бантингса на использование JSON.stringify тоже был хорош. Кроме того, вы можете использовать JSON.stringify через объект YUI JSON, если вы используете YUI. В моем случае мне нужно было сделать дамп в HTML, чтобы было проще просто настроить / вырезать / вставить ответ PhiLho.
function dumpObject(obj, indent)
{
var CR = "<br />", SPC = " ", 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;
}
Я программирую на 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: []
}
}
Я также разместил его как Суть здесь для любых будущих изменений, которые могут потребоваться.
Это может быть симпатичный принтер, но код на самом деле выглядит не очень красиво :)
Вы можете использовать следующие
<pre id = "dump"></pre>
<script>
var dump = JSON.stringify(sampleJsonObject, null, 4);
$('#dump').html(dump)
</script>
Многие люди пишут код в этой ветке, оставляя много комментариев о различных подводных камнях. Мне понравилось это решение, потому что оно казалось законченным и представляло собой единый файл без зависимостей.
Он работал «из коробки» и имеет версии для узла и браузера (предположительно, просто разные оболочки, но я не стал копаться, чтобы подтвердить).
Библиотека также поддерживает удобную печать XML, SQL и CSS, но я не пробовал эти функции.
Для тех, кто ищет отличный способ увидеть свой объект, проверьте prettyPrint.js
Создает таблицу с настраиваемыми параметрами просмотра для печати где-нибудь в вашем документе. Лучше посмотреть, чем в console.
var tbl = prettyPrint( myObject, { /* options such as maxDepth, etc. */ });
document.body.appendChild(tbl);

Простой для печати элементов в виде строк:
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);
В моей библиотеке NeatJSON есть как Ruby, так и Версии JavaScript. Он находится в свободном доступе под (разрешающей) лицензией MIT. Вы можете просмотреть онлайн-демонстрацию / конвертер по адресу:
http://phrogz.net/JS/neatjson/neatjson.html
Некоторые функции (все необязательно):
Посмотрите этот другой ответ на StackOverflow, автор: Хассан
TL; DR:
JSON.stringify(data,null,2)
здесь третий параметр - табуляция / пробелы
Не уверен, что вас уведомляют об изменении ответов. Поэтому я пишу этот комментарий, чтобы сообщить вам, что я добавил свою собственную версию дампа с отступом. :-)