{"id":1078,"date":"2012-03-14T15:21:37","date_gmt":"2012-03-14T14:21:37","guid":{"rendered":"https:\/\/sgaul.de\/?p=1078"},"modified":"2014-03-13T21:34:50","modified_gmt":"2014-03-13T20:34:50","slug":"komplexe-javascript-datenstrukturen-als-string-darstellen","status":"publish","type":"post","link":"https:\/\/sgaul.de\/2012\/03\/14\/komplexe-javascript-datenstrukturen-als-string-darstellen\/","title":{"rendered":"Komplexe Javascript-Datenstrukturen als String darstellen"},"content":{"rendered":"

Zwar bieten Firebug und Co. viele und mittlerweile auch richtig gute Wege an, wie man Javascript und auch darin auftretende Variablen debuggen und inspizieren kann. Leider hat man diese M\u00f6glichkeit nicht immer zur Hand. In meinem derzeitigen Projekt logge ich etwa direkt in die Konsole – hier ist also Handarbeit gefragt, wenn man etwas mehr \u00fcber ein komplexes Objekt wissen m\u00f6chte.<\/p>\n

Menschenlesbares toString<\/h2>\n

Die folgende Funktion formt beliebig komplexe Datenstrukturen in einen String um, den man anschlie\u00dfend etwa mittels dump<\/code> ausgeben kann.<\/p>\n

function toString(obj) {\r\n  return (function traverse(obj, depth) {\r\n    var type   = typeof obj,\r\n        string = '',\r\n        indent = '',\r\n        i;\r\n    for (i = 0; i < depth; i += 1) indent += '  ';\r\n    if (type === 'undefined') string += 'undefined';\r\n    else if (obj === null) string += 'null';\r\n    else if (type === 'object') {\r\n      if (Object.prototype.toString.call(obj) === '[object Array]') { \/\/ array\r\n        var length = obj.length, i;\r\n        string += '[\\n';\r\n        for (i = 0; i < length; i += 1) {\r\n          string += indent + '  ' + traverse(obj[i], depth + 1) + ',\\n';\r\n        }\r\n        string += indent + '](' + length + ')';\r\n      } else { \/\/ normal object\r\n        var prop;\r\n        string += '{\\n';\r\n        for (prop in obj) {\r\n          if (obj.hasOwnProperty(prop)) {\r\n            string += indent + '  ' + prop + ': '\r\n                      + traverse(obj[prop], depth + 1) + ',\\n';\r\n          }\r\n        }\r\n        string += indent + '}';\r\n      }\r\n    }\r\n    else string += obj;\r\n    return string;\r\n  }(obj, 0));\r\n}<\/pre>\n

Die Funktion definiert eine neue Funktion, die f\u00fcr die Rekursion ben\u00f6tigt wird und direkt aufgerufen wird. Dieses Muster ((function(){ \/* ... *\/ }());<\/code>) ist als Immediate Function<\/em> bekannt. Dann wird einfach gepr\u00fcft, welcher Datentyp vorliegt und ggf. rekursiv der Wert in den String gepackt.<\/p>\n

F\u00fcr den Array-Test habe ich mich f\u00fcr Object.prototype.toString.call(obj) === '[object Array]'<\/code> entschieden. Dieser Test ist absolut zuverl\u00e4ssig und im Gegensatz zum Array.isArray(obj)<\/code> aus dem ECMA-Script-5-Standard \u00fcberall vorhanden. Laut MDN<\/a> ist Array.isArray erst im Internet Explorer 9 implementiert.<\/p>\n

Anwendung<\/h2>\n

Mit dieser Funktion kann man sich nun eine beliebige Log-Funktion zusammenbauen:<\/p>\n

function log(message) {\r\n  dump(toString(message));\r\n}<\/pre>\n

Im Ergebnis kann das ganze dann etwa so aussehen:<\/p>\n

{\r\n  a: true,\r\n  b: 42,\r\n  c: hallo,\r\n  d: {\r\n    e: 100,\r\n  },\r\n  f: [\r\n    1,\r\n    2,\r\n    3,\r\n    true,\r\n    false,\r\n    a,\r\n  ](6),\r\n  g: {\r\n    h: {\r\n      i: {\r\n        j: 1,\r\n      },\r\n    },\r\n  },\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"

Zwar bieten Firebug und Co. viele und mittlerweile auch richtig gute Wege an, wie man Javascript und auch darin auftretende Variablen debuggen und inspizieren kann. Leider hat man diese M\u00f6glichkeit nicht immer zur Hand. In meinem derzeitigen Projekt logge ich etwa direkt in die Konsole – hier ist also Handarbeit gefragt, wenn man etwas mehr \u00fcber ein komplexes Objekt wissen m\u00f6chte.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[91],"tags":[367,369,158],"_links":{"self":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/1078"}],"collection":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/comments?post=1078"}],"version-history":[{"count":7,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/1078\/revisions"}],"predecessor-version":[{"id":2525,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/1078\/revisions\/2525"}],"wp:attachment":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/media?parent=1078"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/categories?post=1078"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/tags?post=1078"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}