【问题标题】:JavaScript data formatting/pretty printerJavaScript 数据格式化/漂亮的打印机
【发布时间】:2012-03-07 12:50:30
【问题描述】:

我正在尝试找到一种方法,以人类可读的形式“漂亮地打印”JavaScript 数据结构以进行调试。

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

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

【问题讨论】:

  • 不确定您是否收到编辑答案的通知。所以我写这篇评论是为了通知你我添加了我自己的缩进转储版本。 :-)
  • 注意:JSON.stringify() 答案似乎非常有用,尽管它不被接受为“答案”。
  • 您可以使用 nodedump 获得直观直观的对象输出:github.com/ragamufin/nodedump

标签: javascript debugging json


【解决方案1】:

像这样使用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 文件——它可以与任何库等一起使用。

【讨论】:

  • 这几乎绝对是您将获得的最佳答案。我已经教过 4 或 5 个非程序员阅读和编辑 JSON.stringified 数据结构并将它们广泛用于配置文件。
  • 奇怪的是它会导致问题 - 它确实将名称“JSON”引入全局命名空间,因此可能会给您带来问题。检查您的命名空间是否有“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/) 上失败。
【解决方案2】:

我写了一个函数来以可读的形式转储一个 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$/, "");
}

在递归调用的行上选择缩进,并通过在此行之后切换注释行来支持样式。

...我看到您制作了自己的版本,这很好。游客将有一个选择。

【讨论】:

  • 我喜欢 ;) 无法让它正常工作,但如果你不介意,我会无耻地窃取这个概念并自己编写 :)
  • 这种方法的一个缺点(与 Jason 建议的 JSON.stringify 方法相比)是它不能正确显示对象数组。当你有一个对象数组时,它会显示为 [object Object]。
  • @Ryan:你是说浏览器的原生对象?是的,回头看我的代码,我看到我添加了一条注释: // 如果一个字段是一个对象,那就太糟糕了... :-P 可以在这里进行测试... 转储用户制作的结构是可以的。如果您需要更强大的功能,我看到下面还有其他选择。
  • 我不能用这个。当我尝试转储一些 json 数据时出现无限循环。
  • @RaphaelDDL & PhiLho - 最大调用堆栈大小也可以在小对象上触发;一个具有对自身的属性引用。这样的引用会导致这个函数的无限循环。
【解决方案3】:

你可以使用下面的

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

【讨论】:

    【解决方案4】:

    Firebug,如果你只是console.debug ("%o", my_object),你可以在控制台点击它,进入一个交互式对象浏览器。它显示整个对象,并允许您展开嵌套对象。

    【讨论】:

    • 问题在于它只显示“最顶层”对象 - 我有几十个嵌套对象,我真的需要能够一次看到全部内容,重要的是,看看在哪里事情正在发生变化。所以在这种情况下,Firebug 真的不适合我。
    • (是的,我知道您可以点击展开它们,但每次我想转储数据时点击 10 个左右的链接就是我现在正在做的事情 - 进度非常缓慢)
    • 这也适用于 Chrome(因此可能适用于 Safari)。
    【解决方案5】:

    对于 Node.js,使用:

    util.inspect(object, [options]);
    

    API Documentation

    【讨论】:

      【解决方案6】:

      对于那些正在寻找一种很棒的方式来查看您的对象的人,check prettyPrint.js

      创建一个带有可配置视图选项的表格,以打印在文档的某个位置。比console 更好看。

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

      【讨论】:

        【解决方案7】:

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

        我还将其发布为Gist here,以备将来可能需要的任何更改。

        【讨论】:

        • 它可能是一个漂亮的打印机,但代码实际上看起来并不漂亮:)
        【解决方案8】:

        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
        

        【讨论】:

          【解决方案9】:

          在 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
          • if (!pad) pad = '';比 pad = (pad || ''); 更便宜、更灵活、更易读尽管是一分钟。如果您坚持使用该表格,请删除多余的括号。垫=垫|| '';使用分号的 3 个原因:当 JS 发现省略分号会引发错误时,它会自动插入分号。 1)这比自己添加要慢一点,并且 2)当下一行碰巧在组合时不会引发错误时,可能会导致错误。 3) 将防止您的代码被缩小。
          【解决方案10】:

          这实际上只是对 Jason Bunting 的“使用 Crockford 的 JSON.stringify”的评论,但我无法对该答案添加评论。

          如 cmets 中所述,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;
          

          【讨论】:

            【解决方案11】:

            我认为 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;
            }
            

            【讨论】:

              【解决方案12】:

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

              browser

              nodejs

              它“开箱即用”并且具有节点和浏览器版本(可能只是不同的包装器,但我没有深入确认)。

              该库还支持漂亮的打印 XML、SQL 和 CSS,但我还没有尝试过这些功能。

              【讨论】:

                【解决方案13】:

                对于在 2021 年或 2021 年后检查此问题的任何人

                Check out this Other StackOverflow Answerhassan

                TLDR:

                JSON.stringify(data,null,2)
                

                这里第三个参数是制表符/空格

                【讨论】:

                  【解决方案14】:

                  将元素打印为字符串的简单方法:

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

                  【讨论】:

                    【解决方案15】:

                    我的NeatJSON 库既有Ruby 又有JavaScript versions。它在(许可的)MIT 许可下免费提供。您可以通过以下方式查看在线演示/转换器:
                    http://phrogz.net/JS/neatjson/neatjson.html

                    一些功能(全部可选):

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

                    【讨论】:

                      【解决方案16】:

                      flexjson 包含一个 prettyPrint() 函数,它可能会给你想要的东西。

                      【讨论】:

                        猜你喜欢
                        • 2011-01-07
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-05-06
                        • 1970-01-01
                        • 2016-02-25
                        • 2021-09-19
                        • 2021-06-22
                        相关资源
                        最近更新 更多