Here are the slides from my talk “Advanced JavaScript”. I have given these talks at FrOSCon 2008 and at BarCamp Berlin 2008.
Here are the slides from my talk “Advanced JavaScript”. I have given these talks at FrOSCon 2008 and at BarCamp Berlin 2008.
Bei komplexeren Anwendungen, ensteht schonmal das Bedürfnis, auf dem Rechner des Nutzers generierte JavaScript-Objekte, Arrays und sonstige Variablen an einen Server zu schicken. Nur leider funktioniert das nicht so ganz mit XMLHttpRequest, da POST nur eindimensionale Parameter unterstützt.
Allerdings bietet PHP mit unserialize() eine schöne Funktion, um aus Plaintext beliebig komplexe Variablen zu erzeugen. Jetzt muss man nur noch das JavaScript-Objekt in einen solchen serialisierten String umwandeln und auf dem Server wieder entserialisieren:
serialize = function(elem) {
if (elem == null || elem == undefined || elem.constructor == Function) return 'N;';
switch (elem.constructor) {
case String: return 's:' + elem.length + ':"' + elem + '";';
case Number: return (elem % 1 ? 'd:' : 'i:') + elem + ';';
case Boolean: return 'b:' + (elem ? '1' : '0') + ';';
case Date: return serialize(elem.getTime());
case RegExp: return serialize(elem.toSource());
case Error: return serialize(elem.message);
case Array:
case Object:
var content = '', i = 0;
for (var j in elem) { content += serialize(j) + serialize(elem[j]); i++; }
return 'a:' + i + ':{' + content + '}';
default:
return serialize(elem.toString());
}
}
Standardobjekte, die beispielsweise mit { } erstellt wurden, werden zu Arrays konvertiert, da es nicht so viel Sinn gibt, sie in PHP als Objekte anzusprechen - sie sind ja letztendlich nur Hashes. Wenn das JS-Objekt allerdings etwas komplexer ist, also nicht den Konstruktor Object hat, kann man die Serialisierungsfunktion natürlich trotzdem nutzen. In der toString()-Methode des jeweiligen Objekts, kann man beliebige einfachere Datentypen zurückgeben, die dann stattdessen serialisiert werden.
Achtung! Es ist nicht getestet, ob über unserialize() eventuell schadhafter Code auf dem Server ausgeführt werden kann. Also vorher gründlich testen oder doch JSON benutzen.
getElementsBySelector(selector): Wie viel einfacher wäre es doch, wenn es eine solche Funktion geben würde. Einfach den CSS-Selektor angeben und eine HTMLCollection mit allen zutreffenden Elementen zurückbekommen. Allerdings gibt es von Dean Edwards eine Funktion, die sie größtenteils simuliert: cssQuery. Der Nachteil dieses Workarounds ist die Größe: 16 KB unkomprimiert und 6 KB komprimiert - gerade noch vertretbar.
firstElement, nextElement, usw.: Ein gewisser Vorteil einerseits aber oft ein gewaltiger Nachteil ist, dass das DOM alles als Knoten betrachtet. Auch ein Leerzeichen zwischen zwei Elementen generiert einen neuen Knoten, genauso wie ein Kommentar. Wenn man nun das erste Element/Tag innerhalb eines anderen Elements zu bekommen, stößt man auf ein Problem: firstChild liefert möglicherweise einen Textknoten (mit Leerzeichen) und nicht das erste Element zurück.
Die Möglichkeit mit einer for...in-Schleife die Elemente einer HTMLCollection zu durchlaufen: Wenn man das probiert, erhält man nicht jedes Element sondern die Indizes des HTMLCollection-Objekts. Das lässt sich teilweise durch Wrapper-Funktionen, die das ganze in ein Array umpackt, ersetzen.
Ein Klassenmanagement-System: Man muss sich immer erst selbst Funktionen schreiben, die solche grundlegenden Abfragen ermöglichen. Wäre es nicht viel eleganter einfach auf element.hasClass('klasse') zu prüfen? Mit Prototypen kann man so etwas aber recht einfach realisieren. Notwendige Funktionen wären mindestens hasClass (zum Überprüfen ob das Element die Klasse besitzt), addClass (um eine Klasse hinzuzufügen) und removeClass (um eine Klasse zu entfernen). Zusätzlich wäre noch toggleClass (wenn das Element die Klasse hat, wird sie entfernt, ansonsten hinzugefügt).
Ein kleines JavaScript um die Position eines Objekts auf der Seite zu bestimmen:
function getPosition(obj) {
var pos = { x:0, y:0 };
do {
pos.x += obj.offsetLeft;
pos.y += obj.offsetTop;
} while (obj = obj.offsetParent);
return pos;
}
Benutzt wird das ganze mit:
var pos = getPosition(document.getElementById('objekt'));
alert(pos.x + '/' + pos.y);