[JavaScript]JSON的なダンプをとる関数を作ってみた

IEでデバックをするとFirebugみたいにオブジェクトを展開してみたかったので作ってみた。

特徴は。

  • インデントのオンオフ。
  • プロパティ(キー)のソートのオンオフ
  • 関数のソース表示切り替え
  • 変数(オブジェクト)が参照が深い場合の制限(制限を超えるとthrowされる)

コード

var dumpJson = function(v, opts){
 var _opts={ksort:false, indent:false, funcsrc:false, undefined2str:false, maxDepth:10};
 for(var k in opts) _opts[k]=opts[k];
 var d=parseInt(_opts.maxDepth);
 _opts.maxDepth=(d>0)?(d<100)?d:100:1;
 
 var f1=(!!_opts.indent)?function(d){
  for(var s='\n', i=0; i<=d; i++) s+='  ';
  return s
 }:function(){ return ''; };

 var f2ps=[[/\\/g,"\\\\"],[/\n/g,"\\n"],[/\r/g ,"\\r"],[/\t/g,"\\t"],[/(")/g,"\\$1"]];
 var f2=function(v){
  for(var i=0;i<f2ps.length;i++) v=v.replace.apply(v,f2ps[i]);
  return v;
 }
 
 var fn=function(v,d){
  if(d>=_opts.maxDepth) throw 'depth '+_opts.maxDepth+' orver error.';
  if(null===v) return 'null';
  switch(typeof v){
   case 'undefined': return (!!_opts.undefined2str)?'"undefined"':'null';
   case 'boolean': return v?'true':'false';
   case 'function': v=(!!_opts.funcsrc)?v.toSource():'function()';
   case 'string': return '"'+f2(v)+'"';
   case 'object':
    var s=[];
    if(v instanceof Array){
     for(var i=0; i<v.length; i++) s.push(fn(v[i],d+1));
     return '['+f1(d)+s.join(','+f1(d))+f1(d-1)+']';
    }
    var ks=[];
    for(var k in v) ks.push(k);
    if(!!_opts.ksort) ks.sort();
    for(var i=0; i<ks.length; i++) s.push(fn(ks[i],d+1)+':'+fn(v[ks[i]],d+1));
    return '{'+f1(d)+s.join(','+f1(d))+f1(d-1)+'}';
  }
  return v;
 }
 return fn(v,0);
};

使い方

第一引数にダンプしたい変数、第二引数にオプション。
オプションは、インデント[indent]、プロパティ(キー)のソート[ksort]、functionの場合の切り替え[funcsrc]、変数が循環参照だった場合の最大深度[maxDepth]

var v={
 aaa:'AA\nA',
 bbb:['01', '02', '03', 4, true, null ],
 '1':{
  '2':{
   '3':{
    '4':{
     '5':'aaa'
    }
   }
  }
 }
};
v['ff']=function(){alert('aa');};

try{
 console.log(dumpJson(v,{indent:true}));
}catch(e){
 console.log(e);
}

実行結果

{
  "aaa":"AA\nA",
  "bbb":[
    "01",
    "02",
    "03",
    4,
    true,
    null
  ],
  "1":{
    "2":{
      "3":{
        "4":{
          "5":"aaa"
        }
      }
    }
  },
  "ff":"function()"
}

メモ

取り合えず作ってみたけどmaxDepthは関数も渡してthrowするとかreturnするとか出来るようにしたほうが良かったかも。

eval関数を使えば簡単にJSON文字列をインデントできるな。