Freitag28. Januar 2011

Ich bin ganz sicher nicht der klassische Programmierertyp und so lerne ich Programmiersprachen – im konkreten Fall JavaScript –, in dem ich mich herausfordernden Projekten stelle, um dabei Neues zu lernen. Leider ist dieses “Neue” nicht immer ganz logisch und führt schonmal dazu, dass sich Stirn und Tischplatte unaufhaltsam anzuziehen scheinen. So auch das Thema Pointer in JavaScript, welches mir gestern Abend aufgestoßen ist.

Wenn man ein wenig Erfahrung aus anderen Programmiersprachen wie C mitbringt, dann ist einem der Unterschied zwischen einem Objekt und dem Pointer auf ein Objekt bekannt. Das entscheidende dabei: Bei C kann man sehr einfach festlegen, ob man einer Variable eine Objektkopie zuweist oder nur einen Pointer auf das Originalobjekt erzeugt. Bei JavaScript sieht das etwas anders aus.

Obgleich in JavaScript so ziemlich alles als Objekt betrachtet werden kann, so gibt es doch feine aber entscheidene Unterschiede, wie diese intern behandelt werden. Folgender Code machte mich stutzig:

var layoutCSS = {
    'width': 'auto',
    'min-width': '720px',
    'max-width': '80em'
};
var minSettings = layoutCSS;
minSettings['max-width'] = 'none';
console.log(minSettings); //"none"
console.log(layoutCSS); //"none"

Wie man sieht, wird in diesem Beispiel nicht etwa eine Kopie des Objekts layoutCSS in minSettings angelegt, sondern lediglich ein Pointer auf das Originalobjekt. In der Konsequenz ändert sich der Inhalt des OriginalObjekts layoutCSS bei Zuweisungen an minWidth. Gut zu wissen, denn in JavaScript ist dieses Verhalten auf Arrays und Objekte begrenzt. Strings hingegen werden kopiert, obwohl sie intern ebenfalls wie Objekte behandelt werden. Aufklärung darüber, wie JavaScript mit Pointern umgeht, liefert der Artikel Understanding Pointers in JavaScript.

Soweit so nervig gewöhnungsbedürftig. Wie aber kommt man jetzt zu seiner Kopie bzw. Clone eines Arrays oder eines Objekts? Leider ist es auch hier so – ähnlich wie beim Versuch, ein assoziatives Array zu sortieren – dass JavaScript den Programmierer bei dieser Frage weitgehend im Stich läst. Handarbeit ist demnach angesagt. Einen ersten Lösungsansatz liefert der Artikel von Brian Huisman "How to copy arrays and objects in Javascript", der eine .clone() Methode einführt:

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (item in this) {
    if (item == 'clone') continue;
    if (this[item] && typeof this[item] == "object") {
      newObj[item] = this[item].clone();
    } else newObj[item] = this[item]
  } return newObj;
};

Speziell für jQuery-Nutzer gibts von John Resig höchstpersönlich noch einen kürzeren Vorschlag über die jQuery.extend():

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Zwar finde ich persönlich diese Inkonsistenz bei JavaScript etwas nervig, dass man selbst nicht über Kopie oder Pointer wählen kann, aber was soll's. Wenigstens gibt es halbwegs einfache Lösungswege aus diesem Dilemma. An dieser Stelle ein ganz dickes Dankeschön an das kalifornische JavaScript-Lexikon Dirk Ginader, der mir mit diesen Links den Abend gerettet hat.


Seite 1 von 1 Seiten