Array – Sebastians Blog https://sgaul.de Neues aus den Softwareminen Thu, 13 Mar 2014 20:34:50 +0000 de-DE hourly 1 https://wordpress.org/?v=6.1.1 https://sgaul.de/wp-content/uploads/2019/02/cropped-sgaul-2-1-32x32.jpg Array – Sebastians Blog https://sgaul.de 32 32 Javascript: 1 == [1] https://sgaul.de/2012/05/28/javascript-1-equals-array/ https://sgaul.de/2012/05/28/javascript-1-equals-array/#comments Mon, 28 May 2012 14:06:21 +0000 https://sgaul.de/?p=1218 Javascript: 1 == [1] weiterlesen]]> Mit dem ungetypten Vergleichsoperator == in Javascript sollte man schon vorsichtig sein. Dass 1 == "1" ist, ist man wohl gewöhnt. Es ist oft sehr hilfreich und sorgt selten für Fehler. Aber es gibt echt skurrile Kandidaten, an deren True-sein man wohl eher nicht denken würde.

  • 0 == ""
  • 0 == []
  • 1 == "1"
  • 1 == "   1   "
  • "1" != "   1   "
  • 1 == [1]
  • "aa" == ["aa"]

Vor allem, dass Arrays gleich ihrem einzigen Element sind, finde ich schon sehr irritierend. Auch beim String-Casting kann man beide nicht auseinanderhalten:

console.dir("" + 1); // "1"
console.dir("" + [1]); // "1"

Tja, Vergleichen will gelernt sein…

]]>
https://sgaul.de/2012/05/28/javascript-1-equals-array/feed/ 2
Referenzen bei Problemen mit großen Datenmengen https://sgaul.de/2012/04/21/referenzen-bei-problemen-mit-grosen-datenmengen/ Sat, 21 Apr 2012 11:21:58 +0000 https://sgaul.de/?p=1141 In einem größeren PHP-Projekt hatte ich kürzlich das Problem, dass große Teile der Datenbanken in Arrays geschoben wurden um von dort aus weiterverarbeitet zu werden. Dies ist generell kein schöner Ansatz, war in der besagten Situation aber nicht mehr zu ändern. Ein Kollege kam auf die rettende Idee, die ich hier kurz notieren möchte, so dass ich sie nicht vergesse.

Der Speicherfresser: Array zurückgeben

function getAllTableRows() {
  // ...
  return $allRows;
}
$allRows = getAllTableRows();

Dieser Ansatz führte nun leider regelmäßig dazu, dass PHP mit einer Speicherfehlermeldung abbrach.

Der sparsame Ansatz: Array als Referenzparameter

function getAllTableRows(&$allRows) {
  // alle Werte in $allRows schreiben
}
$allRows = array();
getAllTableRows($allRows);

Fast schon traurig, dass das für PHP so einen Unterschied macht. Ich vermute, dass das an PHPs Eigenheit liegt, mehr auf Werten als auf Referenzen zu arbeiten. Ironischerweise behauptet das PHP-Manual an ähnlicher Stelle, der Kern sei intelligent genug, dies selbst zu optimieren, zumindest was Rückgaben angeht.

Mangels ausreichend großer Beispiel konnte ich den folgenden Ansatz nicht testen:

function &getAllTableRows() {
  // ...
  return $allRows;
}
$allRows =& getAllTableRows();
]]>
Javascript-Arrays kopieren und aus Objekten erstellen https://sgaul.de/2012/04/07/javascript-arrays-kopieren-und-aus-objekten-erstellen/ Sat, 07 Apr 2012 20:49:53 +0000 https://sgaul.de/?p=1121 Javascript bietet von Haus aus keine Clone- oder Copy-Funktionen an. Nun kann man diese recht aufwändig selbst schreiben, oft bieten feste Javascript-Methoden aber bereits eine Lösung.

Arrays flach kopieren

Die Array-Methode Slice erstellt eine Kopie eines Teil-Arrays. Hier kann man die Indizes  weglassen, um so das gesamte Array als flache Kopie zu erhalten.

var x = [1,2,3], y;
y = x.slice();
y.shift();
console.log(y); // [2, 3]
console.log(x); // [1, 2, 3]

Es gibt anscheinend verschiedene Sichtweisen, ob man Slice mit dem ersten Parameter 0 aufruft oder nicht. Die Firefox-Dokumentation stellt ihn nicht als optional da. Meine Praxistests haben aber keine Probleme gezeigt, wenn man die 0 weglässt.

Parameters-Objekt in Array konvertieren

Man kann diesen Ansatz leicht erweitern und auf arrayartige Objekte anwenden. Der bekannteste Vertreter ist sicherlich das Objekt Arguments, das innerhalb einer jeden Funktion genutzt werden kann, um generisch auf die übergebenen Argumente zuzugreifen. Da Arguments aber ein Objekt ist, enthält es keine Array-Methoden. Wenn man diese braucht, kann man dank Javascripts Call- bzw. Apply-Funktionalität das obige Beispiel auch in diesem Zusammenhang nutzen:

function a() {
  var args = Array.prototype.slice.call(arguments);
  console.log(Array.isArray(arguments)); // false
  console.log(Array.isArray(args));      // true
}
]]>
Komplexe Javascript-Datenstrukturen als String darstellen https://sgaul.de/2012/03/14/komplexe-javascript-datenstrukturen-als-string-darstellen/ https://sgaul.de/2012/03/14/komplexe-javascript-datenstrukturen-als-string-darstellen/#comments Wed, 14 Mar 2012 14:21:37 +0000 https://sgaul.de/?p=1078 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,
      },
    },
  },
}
]]>
https://sgaul.de/2012/03/14/komplexe-javascript-datenstrukturen-als-string-darstellen/feed/ 2