Komplexe Javascript-Datenstrukturen als String darstellen

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öglichkeit nicht immer zur Hand. In meinem derzeitigen Projekt logge ich etwa direkt in die Konsole – hier ist also Handarbeit gefragt, wenn man etwas mehr über ein komplexes Objekt wissen möchte.

Menschenlesbares toString

Die folgende Funktion formt beliebig komplexe Datenstrukturen in einen String um, den man anschließend etwa mittels dump ausgeben kann.

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

Die Funktion definiert eine neue Funktion, die für die Rekursion benötigt wird und direkt aufgerufen wird. Dieses Muster ((function(){ /* ... */ }());) ist als Immediate Function bekannt. Dann wird einfach geprüft, welcher Datentyp vorliegt und ggf. rekursiv der Wert in den String gepackt.

Für den Array-Test habe ich mich für Object.prototype.toString.call(obj) === '[object Array]' entschieden. Dieser Test ist absolut zuverlässig und im Gegensatz zum Array.isArray(obj) aus dem ECMA-Script-5-Standard überall vorhanden. Laut MDN ist Array.isArray erst im Internet Explorer 9 implementiert.

Anwendung

Mit dieser Funktion kann man sich nun eine beliebige Log-Funktion zusammenbauen:

function log(message) {
  dump(toString(message));
}

Im Ergebnis kann das ganze dann etwa so aussehen:

{
  a: true,
  b: 42,
  c: hallo,
  d: {
    e: 100,
  },
  f: [
    1,
    2,
    3,
    true,
    false,
    a,
  ](6),
  g: {
    h: {
      i: {
        j: 1,
      },
    },
  },
}

2 Kommentare

  1. funktioniert das auch mit komplexen Pointer, die irgendwann rekursiv werden? Oder gibt das dann eine Endlosschleife?

  2. Hatte ich auch überlegt. Kann man rekursive Strukturen überhaupt definieren ohne in eine Endlosschleife zu kommen? Mir ist da spontan kein Weg ein gefallen, daher hab ich den Fall nicht beachte…

Kommentare sind geschlossen.