Warum ich Prototype.js hasse
... und jedem Webentwickler davon abrate es jemals zu benutzen.
Der Grund ist einfach: Prototype manipuliert fröhlich an internen JS Objekten herum und zerstört dadurch essentielle Funktionalität.
Ein Beispiel, dass mir bereits seit langem bekannt ist: Prototype zerstört Javascripts for ... in. Ein Beispiel um es zu verdeutlichen:
Mit normalem JS:
>>> a = [4,5]; for(var i in a) { console.log(i, a[i]); }
0 4
1 5
Mit Prototype:
>>> a = [4,5]; for(var i in a) { console.log(i, a[i]); }
0 4
1 5
each function()
eachSlice function()
all function()
any function()
[...]
uniq function()
clone function()
toJSON function()
Prototype fügt also eine Unmenge von Funktionen an ein Array an, welche bei einem for ... in auch durchlaufen werden. Dies ist ärgerlich, aber mit einem klassischen for i < .length geht es noch immer.
Etwas viel schlimmeres ist mir heute aufgefallen: Prototype zerstört die Funktionalität von JSON.stringify(), welches entweder nativ in Firefox 3.5 implementiert ist oder über die json2.js für ältere Browser zur Verfügung gestellt wird. Auch hier ein Codebeispiel:
Normales JS: >>> JSON.stringify([1,"a"]) "[1,"a"]" >>> JSON.parse(JSON.stringify([1,"a"])) [1, "a"] Und mit Prototype: >>> JSON.stringify([1,"a"]) ""[1, \"a\"]"" >>> JSON.parse(JSON.stringify([1,"a"])) "[1, "a"]"
Wie es scheint wird wegen Prototype stringify() zwei mal ausgeführt. Ein weiteres parse() liefert dann den eigentlich gewünschten JSON String. Dieses Verhalten ist absolut inakzeptabel!
Aber was sollte man als Alternative verwenden falls man eine Browser unabhängige JS Bibliothek braucht? Ich rate zu jQuery. Bei jQuery wird sehr darauf geachtet eine klare Trennung zwischen jQuery und nativen Objekten zu gewährleisten. Es pfuscht nicht an nativen Arrays oder JSON herum.
Diese strikte Trennung kann aber zu einigen Unklarheiten führen, wenn man nicht genau weiß ob man nun ein jQuery Array oder ein natives Array in der Hand hat. Ein solches Problem hatte ich kürzlich mit filter(), da sich die native Implementierung deutlich von der in jQuery unterscheidet. Auch hier ein Codebeispiel:
Mit normalen JS:
>>> [1,'a'].filter(function(aArg) {console.log(aArg);});
1
a
Mit jQuery:
>>> $([1,'a']).filter(function(aArg) {console.log(aArg);});
0
1
Wie man sieht übergibt die native Funktion als ersten Parameter das Objekt selbst, während in jQuery nur der Index übergeben wird. Es ist somit darauf zu achten ob man nun ein echtes Array oder ein jQuery Array vor sich hat, in diesem Fall wird aus einem echten Array per $(array) ein jQuery Array. Das echte Array bleibt in jedem Fall unangetastet.
Was mir Heute auch noch unangenehm aufgefallen ist an Prototype: Es kapselt EventListener nicht gut genug, vor allem im Bezug auf Events abbrechen. Im normalen DOM bricht man der event.preventDefault() ein Event ab. Fängt man ein Formular vor dem Abschicken ab, so wird es nach dem Funktionsaufruf nicht abgeschickt.
Leider unterstützt der IE keine echten EventListener und es gibt diese Methode gar nicht. Stattdessen muss die EventHandler Methode einfach false zurückliefern.
In Prototype muss man beide Methoden verwenden um das gewünschte Ergebnis zu erzielen. jQuery hingegen sorgt selbst dafür, dass bei einem return false; das Event nicht weiter ausgeführt wird.
Das war es vorerst mit meiner Abneigung gegen Prototype, vielleicht kommt noch etwas dazu falls ich noch einmal kostbare Arbeitszeit wegen solchen Bugs verliere. Ich werde mir auch ernsthaft überlegen vielleicht das gesamte Projekt an dem ich zur Zeit arbeiten muss von Prototype auf jQuery umzustellen.