Mein erster Versuch hier einen Artikel über Vererbung in JS zu schreiben, scheiterte an einem Punkt den ich übersehen hatte. Daher hier eine neue zweite Version. Ich werde den Artikel aber in drei Teile aufsplitten.
Teil 1. - OOP in Javascript
Teil 2. - MOC my Object Creator
Teil 3. - Vergleiche und Benchmarks
OOP in Javascript
In Javascript gibt es an sich keine Klassen, keine Vererbung, keine privaten Eigenschaften. All die Dinge, die eine Objektorientierte Programmierung ausmachen. Trotzdem wird Javascript als OO Sprache bezeichnet. Warum?
Der Konstruktor
Der Grund dafür ist, dass Objekte existieren und diese um Eigenschaften und Methoden erweitert werden können. Entscheidend ist aber das es möglich ist neue Objekte zu erzeugen. Das Schlüsselwort new KonstrukorFunktion() erzeugt ein neues (Funktions)Objekt. Das ist trivial und funktioniert so:
javascript
function A(){
this.prop = 'hallo';
this.func = function(){alert(this.prop);};
}
var obj = new A();
obj.func();
Eine Funktion, die ein Objekt erzeugt heißt Konstruktorfunktion. Die aber im Grunde keinen Unterschied mit einer herkömmlichen Funktion hat. Lediglich die Bedeutung des Schlüsselwort this innerhalb der Funktion ist eine andere. In Javascript ist this immer der Kontext aus dem eine Funktion aufgerufen wurde. Ein Aufruf einer globalen func() entspricht genau genommen window.func(). Das bedeutet, in der Funktion ist window der Kontext und entspricht dem Wert von this.
Bei einer Konstruktorfunktion, die mit new func() aufgerufen wird, ist der Kontext im Prinzip new. Es wird also ein Objekt erzeugt und this zugewiesen. Die Funktion A() in dem Beispiel, wird dann in diesem Kontext des neu erzeugten Objektes aufgerufen. Dabei werden dem Objekt über this, zwei Eigenschaften hinzugefügt. Eine Zeichenkette und eine Funktion. Jedes neu erzeugte Objekt A() erhält diese Eigenschaften. Da die Zuweisung jedesmal auf's neue zur Laufzeit erfolgt, sollte diese Methode um dem Objekt Eigenschaften zu zuweisen, sparsam verwendet werden - sie kostet viel Zeit. Stattdessen ist es sinnvoller, wenn möglich, Funktionen und Eigenschaften über das prototype Objekt zu deklarieren. Doch das läßt sich nicht immer realisieren, wie im nachfolgenden Beispiel.
private Eigenschaften
Das führt uns zum ersten Trick. Um in Javascript private Eigenschaften zu simulieren, werden diese in der Konstruktorfunktion mit var deklariert. Dadurch sind diese nur lokal sichtbar und können auch nur von den in der Konstruktorfunktion definierten Funktionen benutzt werden. Diese Funktionen sind im OOP Sprachgebrauch privilegierte Funktionen, da sie auf private Eigenschaften zugreifen dürfen.
Ein Beispiel für private Eigenschaften
javascript
function A(){
var privat = 'x';
this.privilegiert = function(){return privat;};
}
var obj = new A();
alert(obj.privilegiert()); // 'x'
Nach dem gleichen Prinzip lasen sich auch private Funktionen erzeugen, wenn eine Funktion lokal in der Funktion erzeugt wird, ist diese nach aussen nicht sichtbar.
Vererbung - der klassische Weg
Der klassiche Weg um in Javascript eine Vererbungshierachie umzusetzen funktioniert aber in so einem Fall nicht mehr und muss vermieden werden. Der Weg sähe in etwa so aus:
javascript
function A(){}
function B(){}
B.prototype = new A(); // B erbt von A
prototype ist eine Art Vorlage oder Template, auf die alle Instanzen des Objektes zugreifen können. Das ist eine prototypische Vererbung.
Das Problem
Das Problem mit dieser Art der Vererbung ist, dass der Konstruktor von A() bei der Zuweisung aufgerufen wird.
Dadurch wird ein Objekt A() zu einem Zeitpunkt erzeugt, wo es noch nicht gebraucht wird und manchmal auch stört. Z.b. wenn die Anzahl der Objekte die erzeugt gezählt werden sollen.
Ausserdem funktioniert der Trick mit den privaten Variabeln nicht mehr, da mit dieser Methode alle Objekte die gleichen privaten Variabeln haben. Ganz besonders aufgepaßt werden muss hier, dass das Objekt A in allen abgeleiteten Instanzen identisch ist, was, wenn man es nicht weiß, zu seltsamen Verhalten und schwer zu findenen Fehlern führen kann.
Ein Beispiel für die klassische Vererbung
Um das Problem zu zeigen hat das Objekt A() ein privates Attribut und ein Paar setter/getter Funktionen. Bei der Zuweisung des Prototypobjekts wird der Konstruktor aufgerufen, nun hat privat in allen Instanzen von B() den gleichen Wert.
javascript
function A(){
var privat = 'x';
this.set = function(p){if(p) privat = p};
this.get = function(){return privat};
}
function B(){}
B.prototype = new A(); // B erbt von A
var a = new B();
var b = new B();
a.set(1);
b.set(2);
alert(a.get()); // => 2
alert(b.get()); // => 2 !
Wegen diesem Problemen enstand der Wunsch, eine eigene Möglichkeit der Vererbung in JS einzuführen, wie es auch in vielen sehr interessanten Artikel im Internet beschrieben wird.
Der falsche Weg
Mein erster Versuch einer Lösung scheiterte an einem besonderen Verhalten des Objektes prototype, dass einerseits vermutlich ziemlich genial ist, wie vieles an JS, aber anderseits diese einfache Lösung verhindert.
Meine Idee war es, nur die prototype Objekte zu zuweisen und im Konstruktor dann mit .apply(this) den Kontext für die privaten Eigenschaften herzustellen. Diese Art der Vererbung klappt eigentlich relativ gut.
Ein Beispiel
Das Objekt A() hat die private Eigenschaft und die Methoden von dem Beispiel oben und noch eine prototypische Methode (diese dient später dazu das Problem bei dieser Art der Vererbung zu erkläutern).
Der Konstruktor A() wird hier tatsächlich nur so oft aufgerufen, wie er soll, nämlich insgesamt zweimal. Die private Eigenschaften bleiben bei der Instanz erhalten und auch die prototype Eigenschaften werden vererbt. Eigentlich alles wunderbar, doch eine besondere Eigenschaft von prototype habe ich übersehen.
Im Grunde steckt hinter den ganzen Techniken von JS keinerlei besondere Magie, wir haben es hier mit Objekten und Funktionsreferenzen zu tun. Techniken, die unter JS weit verbreitet sind und die man auch beherschen sollte. Das einzige Objekt, das eine gewisse Magie enthält, ist das prototype Objekt. Normalerweise dient es zur Erzeugung der prototype-chain, der Prototypkette, an der sich entlang gehangelt wird, um Funktionen in der Vererbungshierachie zu finden. Eine besondere Eigenschaft ist, dass jede Eigenschaft/Funktion die dem prototype Objekt zugewiesen wird, sofort allen Instanzen zu Verfügung steht (das ist logisch, wenn man sich klar macht, dass prototype einfach nur eine Eigenschaft ist, in der Javascript nachschaut, ob eine Funktion existiert - wie gesagt, keine Magie). Das ist die geniale Eigenschaft, aber dummerweise gilt diese Regel auch umgekehrt, A erbt auch von B!
Beispiel für A.prototype = B.prototype und umgekehrt
Der Aufruf a.b(), der eigentlich einen Fehler erzeugen müßte, gibt ein B.prototype.b aus. Aus diesem Grund war der erste Entwurf dieses Artikels fehlerhaft. So schön diese simple Art der Vererbung auch ist, sie führt nicht zum richtigen Ziel.
Zum Ziel führt hier nur eine Erweiterung des Function.prototype Objekt bzw. eine Helperfunktion. Denn um alle Bedingungen, die die Vererbung erfüllen soll, umzusetzen, sind ein paar Verrenkungen nötig.
Bedingungen
Folgende Bedingungen sollte eine Vererbung erfüllen.
Sie sollte Konstruktorfunktionen nutzen
Die prototypische Vererbung sollte weiter möglich sein
private Attribute sollen ebenso möglich sein, wie private und privilegierte Methoden
Ein zugriff auf das "super" Objekt
Der Konstrukor soll nur so oft aufgerufen werden, wie eine Instanz erzeugt wird.
Die Umsetzung des Zieles erläutere ich in der 2. Folge. Und jetzt abschließend noch ein paar wirklich weiterführende Links, mit interessanten Artikeln zum Thema.
Eine sehr gute deutschsprachige Erklärung, des prototype Objekts. Das ist ein Artikel im Rahmen einer Serie, die Objekte in Javascript und deren Funktionsweisen, sehr gut!
Eine verbesserte Variante der klassischen Vererbung (auch in Deutsch). Sie erfüllt fast alle Bedingungen, lediglich der Aufruf der Konstruktorfunktion erfolgt einmal zuviel. Wer eine einfache und effektive Vererbung nutzen möchte und mit diesen Nachteil Leben kann, sollte diese Art in's Auge fassen.
Hier wird der Weg beschrieben, der eine Lösung des Problems zeigt. Die dort beschriebene Methode nutzen auch einige Frameworks, vor allem MooTools setzt auf eine Funktion, die der dort beschriebenen sehr ähnlich ist. Die einzige Kritik, die ich daran habe, ist der dass keine Konstruktorfunktionen und prototypen verwendet werden können. Es muss immer ein Objekt dem Konstruktor Class() übergeben werden, aus dem dann das entsprechende Funktionsobjekt hergestellt wird, mit dem dann die Instanzen erzeugt werden können.
Der Mensch ist ein Gewohnheitstier und mich nehme ich davon nicht aus. Schlimm wird es, wenn Dinge, an die ich mich gewöhnt habe, sich ohne mein Wissen ändern. Automatische Updates, so nützlich sie auch sind, sind eine ideale Quelle für solche kleine Nicklichkeiten im Alltag.
Ich frag mich warum ich diesen Artikel nicht schon viel früher geschrieben habe. Ich habe diese Probleme schon viele Male gelesen und immer wieder musste ich selbst suchen wo das Problem liegt. Ich habe also oft genug selbst mit diesen Problemen zu kämpfen gehabt und habe wertvolle Lebenszeit damit verschwendet, Bugs zu finden, die keine waren.
Deshalb habe ich hier mal die Liste der größten und am schwersten zu findesten IE Bugs beim programmieren von Javascript, zusammengestellt.
Das war mir bisher nicht bewußt, wie wahrscheinlich vielen anderen auch nicht.
Eine leere src-Angabe im Image-Tag verursacht einen Request und zwar in dem Verzeichniss, wo auch die eingebundene Seite liegt. Das gleich gilt für Bilder, die mit Javascript per new Image() erzeugt werden. Nähere Details beschreibt Nicholas C. Zakas auf seiner Seite.
Das Problem sind vor allem Skripte bzw. die darin enthaltenen Templates, wo es schnell vorkommen passieren kann, dass z.b. Eintrag wie ein <img src="$variabel"> ein leeres src-Attribut erzeugt. Es sollte zwar nicht, kann aber u.U. vorkommen, wenn der Code einer dynamischen Seite nicht sauber programmiert wurde oder wenn ein Platzhalter vergessen wurde.
Der einzige Browser, der sich davon nicht beeindrucken läßt, ist Opera.
Vergleiche mit Javascript und ihre Merkwürdigkeiten. Eigentlich sollte man meinen, Vergleiche wären eine klare Sache. Entweder es ist etwas identisch oder nicht. Fertig!
So einfach ist es aber leider nicht. Da in Javascript eine automatische Typkonvertierung existiert, die zumindest in einen Sonderfall zu einem merkwürdigen Ergebnis führt. Entdeckt habe ich dieses Verhalten gestern in einem längeren Thread im selfhtml Forum. Dort war die Frage aufgetaucht, warum ("0" && "1") 1 ergibt (test). Im weiteren Verlauf stellten wir fest, dass die Vergleiche sehr seltsame Ergebnisse hatten. Z.b. der folgende Code:
javascript
var str = '0';
alert(
'str==true => ' + (str == true)
+ '\n'
+ '!str==true => ' + (!str == true)
);
Der Wert ist nicht wahr und er ist aber auch nicht unwahr. Wie kann das sein?
In den letzten Tagen hat die ganze Debatte um die bevorstehende Internetzensur noch mal richtig Schwung angenommen.
Schön zusammengefaßt, hat es die Süddeutsche. In dem Artikel werden noch mal alle Argumente, die gegen das Gesetz vorgebracht werden zusammengefaßt und auch die Kampagne im Internet richtig analysiert. Wie das aber auch in Hose gehen kann, zeigt dieser Kommentar in der Frankfurter Rundschau, von einem Politikprofessor(!). Dieser ist an Ahnungslosigkeit und Unterstellungen kaum zu überbieten. Da waren selbst die Aussagen von von Guttenberg in der Tagesschau harmlos. Das Internet wimmelt nach Auffassung des Profs. von Kommunisten und Anarchisten, die sich den Geschäftemachern in den Weg stellen und Kinderpornos verbreiten wollen:
Trotz gewaltigem Zuspruch bei der Internetpetiton gegen die Zugangssperre mißliebiger Inhalte, scheinen unsere gewähltem Volksvertreter diese Maßnahme sinnvoll zu halten, um ihre Zensurziele durchzusetzen. Laut Heise enthält der Entwurf nur kleine Änderungen im Detail und entspricht den fragwürdigen Vorgaben aus dem Hause der Familienministerin. Der AK Zensur hat darauf alle Gespräche mit dem SPD Verhandlungsführer abgebrochen
Sie planen, am Donnerstag die Büchse der Pandora zu öffnen. Daher sehen wir, die Internet-Community, keinen Grund mehr um weiter mit Ihnen zu reden. Alle weiteren Gespräche zu diesem Thema sagen wir hiermit ab. Dies gilt auch für Ihre Einladung für Mittwoch Nachmittag ins Paul-Löbe-Haus.
DNS Sperren sind nutzlos!
Das Prinzip, dass bei der Sperre eingesetzt werden soll, eine sogenannte DNS Sperre ist völlig ungeeignet um Internetseiten zu "sperren", es wird lediglich der normale Zugang über deutsche Provider etwas erschwert. Keiner der Konderporno Seiten besuchen will läßt sich davon aufhalten. Im gegenteil es würde mich wundern, wenn diese Leute nicht sowieso schon jetzt alles tun, um ihre Machenschaften zu verschleiern und dann wohl kaum von so einer Sperre beeindruckt sein werden.
Auf dieser Seite findet man z.b. eine Liste mit nicht zensierten DNS Servern, davon kann man einen auswählen und in den Netzwerkeinstellungen eintragen. Das ist (noch) völlig legal und ein Aufwand von wenigen Minuten, wenn man weiß wie sowas konfiguriert wird.
Das Schlimme bei dieser Art der Sperre ist, dass der Staat glaubt hier ein Mittel der Kontrolle der Inhalte des Internets in die Hand zu bekommen. Die ersten Äußerungen verschiedener Verbände, nach Wünschen von Sperrungen für ihre Zwecke sind auch schon vorhanden. Was kommt als nächstes?
Übrigens diesen Monat vor genau 60 Jahren ist 1984 von George Orwell das erste Mal erschienen. Ein Buch aktueller denn je.
Aktuell wird überall und dort, ein Video von Douglas Crockford gehyped, in dem dieser einige Aspekte von Javascript beschreibt. Der (englischsprachige) Vortrag unter dem Motto Javascript the good parts, geht tief in die Anwendung von Javascript.
Logisch! Douglas Crockford ist der Javascript Guru, insofern ist diese Aufmerksamkeit berechtigt. Aber seit gestern ist auf you tube ein weiterer hochinteressanter Javascript Vortrag im Google TechTalks Channel vorhanden. Unter dem Titel speed up your Javascript beleuchtet Nicholas C. Zakas die Interna von Javascript näher.
In dem einstündigen Vortrag erklärt Nicholas die Wirkungsweise von Javascript und wo mit diesem Wissen sich die Geschwindigkeit optimieren läßt.
Nachdem ich mich jetzt ein halbes Jahr lang mit dem neuen Firefox 3 rumgeschlagen habe und dabei vieles probiert, deinstalliert, installiert, Bookmarks gelöscht, about:config Tipps und was weiß ich noch alles, gemacht habe. Bin ich nun endlich auf die Lösung meiner Probleme mit diesem Browser gekommen.
Eine der Eigenschaften von Javascript, die sie von anderen Programmiersprachen abhebt, ist die prototypische Vererbung. Kurz gesagt bedeutet das, dass jedes Objekt eine Eigenschaft .prototype besitzt, von dem alle erzeugten Instanzen dieses Objektes erben. Diese Art der Vererbung hat Vorteile und auch viele Nachteile, mit denen sich etliche Artikel im Internet beschäftigen. Deshalb möchte ich auch hier gar nicht näher darauf eingehen, sondern eine Besonderheit dieser Methode zeigen, mit der es möglich ist in Javascript vordefinierte Objekte um Funktionen zu erweitern, die oft vermisst werden.
Das String-Objekt bietet sich für diese Erweiterungen ganz besonders an, da es häufig zum Einsatz kommt und leider auch ein paar häufig benötigte Funktionen nicht kennt.
Der Molmassenrechner brechnet die Molmasse einer Verbindung. Dazu parst das Skript die eingegebene Zeichenkette und versucht die Zusammensetzung der Verbindung zu ermitteln. Daraus läßt sich dann die Molmasse(molare Masse) der Verbindung errechnen.
Das Skript kann mit einem geklammerten Ausdruck und Kristallwasserangaben umgehen. Eine Verbindung mit mehreren Klammern, kann in dieser Version noch nicht berechnet werden. Das Skript rechnet aber einfache und exakter, als die auf Wikipedia verlinkten Molmasse Rechner.
Ich hatte in der Vergangenheit ja schon einmal ein Skript vorgestellt, mit dessen Hilfe es möglich ist BB-Code in eine Textarea einzufügen. Um es einsetzen zu können, werden entsprechende Buttons benötigt, die z.b. über einer Textarea angezeigt werden und mit denen dann der Text entsprechend formatiert wird. Dazu habe ich das Skript erweitert und verbessert, sodass sich automatisch und leicht konfigurierbar, über eine Textarea, JS Buttons einfügen lassen.
Ich nutze den Code als Basis für Greasemonkey-Skripte, für einige Foren, die keine entsprechenden Buttons anbieten (z.b. das Forum auf Perlunity)
Das Skript ist relativ kompakt (knapp über 100 Zeilen mit Kommentaren) und funktioniert bei meinen Tests unter Windows XP, in allen gängigen Browser.
Firefox 3.x (und soweit ich das rausbekommen habe auch die Versionen davor) zeigt unter Umständen in einem pre-Tag, keinen Scrollbalken an, wenn die Schriftgröße geändert wird. Das passiert, wenn der Inhalt nur über eine Zeile geht und die Schriftgröße verkleinert wurde.
Oft entfachen sich hitzige Diskussionen in Foren darüber, welche Funktion für einen Zweck geeigneter und/oder schneller ist. Dann muss ein Benchmark her, mit dem die Geschwindigkeit der unterschiedlichen Funktionen verglichen werden kann. Als langjähriger Perl Programmierer benutze ich häufig das Modul Benchmark mit dem sich das relativ leicht realisieren läßt. Ich habe ein Javascript geschrieben, das ähnlich arbeitet und hier vorstellen möchte.
Im selfhtml Forum hatte jemand nach einer LED Anzeige mit JS gefragt. Da meine Suche im Netz nur entweder Flash Beispiele oder untaugliche JS Skripte erbrachte, habe ich ein kleines LED Anzeige Skript geschrieben.
Ich habe das Rubberband überarbeitet und hier ein Beispiel, wie aus einem vorhandenen Bild damit ein Ausschnitt markiert werden kann. Das Rubber-Objekt ist nach Außen weitestgehend gleich geblieben,
intern sind aber neue Dinge hinzugekommen. Eine Funktion createBox(), erzeugt das
DIV das für das Rubberband gebraucht wird, mit der entsprechenden Funktionalität und die Klasse Rect() bietet Methoden an, um Berechnungen mit dem Rechteck durch zu führen
Heute überraschte mich meine Firefoxinstallation auf der Arbeit mit einem update auf Firefox 3!
Bisher habe ich den Sprung von 2.x auf 3.x vermieden, weil ich einerseits, nicht immer die neuste Version brauche und anderseits, diese oft auch noch ein paar kleinere Versionsprünge brauchen, um wirklich stabil zu sein. Aber hier hat mir irgendeine Autoupdate Einstellung einen Strich durch die Rechnung gemacht und jetzt sitze ich vor einem Firefox 3.0.
Zum Glück sind mir vorher schon einige Beschwerden über die URL Leiste aufgefallen und ich wußte was auf mich zukommt.
Der Filter in der Leiste hat im FF 3 ein völlig anderes Verhalten. Im Firefox 2 werden während der Eingabe einer URL, nur die URLs der besuchten Seiten gefiltern, im Firefox 3 dagegen auch die Bookmark URLs und die Titel der besuchten Seiten und der Bookmarks durchsucht. Dadurch werden die Vorschläge, die beim eintippen gemacht werden, sehr umfangreich und unübersichtlich. Was in meinen Augen auch an dem Erscheinungsbild liegt, das sich geändert hat und wie ich finde nicht zum Vorteil. Daher bestand der Wunsch, diese Neuerungen, die sich awesomebar schimpft, rückgängig zu machen
Heutzutage, wo das Internet voller kriminieller Machenschaften ist und alle meinen oder deinen Rechner kidnappen wollen, ist ein bisschen Vorsicht angesagt. Da ich weder Firewalls noch Antivrenprogramme nutze, muss ich ab und an mal Windows checken, ob auffällige Dinge passieren. Ein Tool was ich dafür verwende ist TCPView, dass mir alle Verbindungen meines Rechners anzeigt. Heute fiel mir eine Liste von Verbindungen in's Auge, die ich mir nicht erklären konnte.
Relativ schnell geklärt war, was es mit dieser Domain auf sich hat. amazonaws.com ist ein Service von Amazon, allerdings war mir die Seite zu technisch, um sofort zu erkennen was nun dahinter steckt. Ein Hinweis, den ich in einem Forum entdeckte, führte mich auf die Spur, dass der Firefox etwas damit zu tun haben könnte. Und richtig, wenn der Firefox beendet wird, verschwinden die Verbindungen aus der Liste und tauchten auch nicht wieder auf.
sicher kein interessantes Thema, aber weil ich es heute zum ersten Mal sah, hier mal eine Screenshot eines Web-Betrugs Auf die Webseite bin ich gekommen, weil ich angeblich eine Grußpostkarte von web.de bekommen habe. Die Mail war zwar dort im Spamfilter, aber der Name der Absenderin hätte von einer mir bekannten Person stammen können. Ich bin auf jeden Fall beeindruckt, wie deutlich das der Firefox macht - ich hätte zwar sowieso nicht meine Daten eingegeben, weil ich auf sowas tasächlich mal reingefallen bin (ja lacht nur), aber schön zu Wissen, dass man in Zukunft besser vor solchen Betrugsversuchen geschützt ist.