JavaScript数据格式/漂亮打印机


124

我正在尝试找到一种pretty print易于理解的JavaScript数据结构调试方法。

我有一个相当大和复杂的数据结构存储在JS中,我需要编写一些代码来对其进行操作。为了弄清楚我在做什么和哪里出了问题,我真正需要的是能够完整地查看数据结构,并在每次通过UI进行更改时对其进行更新。

除了找到一种将JavaScript数据结构转储到人类可读的字符串的好方法外,我还能处理所有这些事情。JSON可以,但是确实需要很好地格式化和缩进。为此,我通常会使用Firebug出色的DOM转储工具,但我确实需要能够立即查看整个结构,这在Firebug中似乎是不可能的。

欢迎任何建议。

提前致谢。


不知道您是否收到关于答案编辑的通知。因此,我写此评论以通知您,我添加了自己的缩进转储版本。:-)
PhiLho

注意:JSON.stringify()答案似乎非常有用,尽管它不被接受为“ the”答案。
GuruM

您可以使用nodedump获得直观,直观的对象输出:github.com/ragamufin/nodedump
ragamufin 2013年

Answers:


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
这种方法的一个不足之处(与Jason建议的JSON.stringify方法相比)是,它无法正确显示对象数组。当您有一个对象数组时,它显示为[object Object]。
瑞安(Ryan)2010年

@Ryan:您的意思是浏览器的本机对象?是的,回头看我的代码,我看到我添加了一条注释://如果一个字段是一个对象,这太糟糕了... :-P在这里进行我的测试还可以...转储用户制作的结构是可以的。如果您需要更强大的功能,我发现下面还有其他选择。
PhiLho

我不能用这个。当我尝试转储一些json数据时,出现无限循环。
neoneye 2011年

1
@RaphaelDDL&PhiLho-最大调用堆栈大小也可以在一个小对象上触发;一个带有自身引用的属性。这样的引用将导致此功能的无限循环。
skibulk 2013年

233

像这样使用Crockford的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数据结构,并将它们广泛地用于配置文件。
Joel Anair

1
奇怪的是,这会引起问题-它确实在全局命名空间中引入了名称“ JSON”,因此可能会引起问题。添加名称空间之前,请检查名称空间中的“ JSON” 以查看是否存在冲突。
詹森·邦廷

1
好吧,原型就是那样的邪恶……;)
Jason Bunting

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/)
Kragen Javier Sitaker 2011年


15

在中Firebug,只要console.debug ("%o", my_object)您可以在控制台中单击它,然后输入一个交互式对象资源管理器。它显示了整个对象,并允许您扩展嵌套的对象。


1
问题在于,它仅显示“最顶层”对象-我有数十个嵌套对象,我真的需要能够一次查看全部内容,而且重要的是,查看事物在哪里发生变化。因此,在这种情况下,Firebug确实不适用于我。

(是的,我知道您可以单击以展开它们,但是每次我要转储数据时都单击10个左右的链接是我现在正在做的-进展非常缓慢)
Dan

1
这也适用于Chrome(因此可能适用于Safari)。
Kragen Javier Sitaker 2011年


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

在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 ||))__
Jason Bunting

我的观点是if(!foo)foo = ... vs foo =(foo || ...),但是用分号结束所有行的原理是什么?

1
如果您不这样做,则会遇到某种讨厌的语言特质,更不用说您将无法轻松地缩小代码(除非您碰巧使用的缩小器足以为您添加分号)。有关更多详细信息,请参见stackoverflow.com/questions/42247
杰森邦廷

1
如果(!pad)pad =''; 比pad =(pad ||'')更便宜,更灵活并且更具可读性;尽管数量不多。如果您坚持使用该表格,请删除多余的括号。垫=垫|| ''; 分号的3个原因:当JS看到省略掉分号会引发错误时,它们会自动插入行尾分号。1)这比自己添加它要慢一些,并且2)当下一行碰巧组合时不会引发错误时,可能导致错误。3)将防止您的代码被缩小。
SamGoody 2010年

1

这实际上只是对Jason Bunting的“使用Crockford的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;

1

我认为J.Buntings使用JSON.stringify的响应也很好。顺便说一句,如果碰巧正在使用YUI,则可以通过YUI的JSON对象使用JSON.stringify。就我而言,我需要转储为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

很多人在此线程中编写代码,并有许多有关各种陷阱的评论。我喜欢这个解决方案,因为它看起来很完整,并且是一个没有依赖性的单个文件。

浏览器

节点

它“开箱即用”地工作,并且具有节点和浏览器版本(大概只是不同的包装器,但我没有挖掘确认)。

该库还支持漂亮的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

一些功能(全部可选):

  • 包装到特定宽度;如果对象或数组可以放在一行上,则将其保留在一行上。
  • 对齐对象中所有键的冒号。
  • 按字母顺序将键排序到对象。
  • 将浮点数格式设置为特定的小数位数。
  • 换行时,请使用“短”版本,将数组和对象的开/关括号与第一个/最后一个值放在同一行。
  • 以细粒度的方式控制数组和对象的空白(在方括号内,冒号和逗号前后)。
  • 在Web浏览器中并作为Node.js模块工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.