Dart ist eine von Google entwickelte Programmiersprache, die mittlerweile als Open Source Projekt verfügbar ist. Derzeit befindet sich die Sprache im technischen Preview und ist noch nicht produktiv zu verwenden, aber man kann schon prima damit rumspielen.
Aus Dart kann JavaScript generiert werden (ähnlich dem CoffeeScript Ansatz) oder es kann native im Browser laufen. Es gibt bereits Webkit- und Chrome-Branches, die genau jenes unterstützen sollen. Trotzdem: es wird noch einige Zeit vergehen, bis man wirklich von einer weiten “nativen” Unterstützun von Dart in den Browsern sprechen kann. Glücklicherweise kann man aus Dart ja auch JavaScript machen, weswegen die Sprache trotzdem interessant ist.
Aber warum das Ganze? JavaScript ist immerhin weit verbreitet und hat viele Anhänger gefunden.
Vor ca. einem Jahr begann ich mich ernsthaft mit JavaScript beschäftigen. Ich komme von der Java Welt und musste daher einiges lernen, bevor ich wirklich produktiv arbeiten konnte. Die Art zu Denken unterscheidet sich doch sehr zwischen Java und JavaScript.
Manche Leuten sagen, dass man sich besonders tief mit JavaScript beschäftigen muss, ansonsten könne man nicht über die Vor- und Nachteile diskutieren. Ich bin nun wirklich kein JavaScript Ninja. Aber ich glaube fest daran, dass eine Sprache leicht zu erlernen und leicht zu verstehen sein sollte. Zudem sollte eine Sprache konsequent sein, wenn es um Syntax und Konzepte geht.
Auch jetzt, nachdem ich bereits so lange Zeit mit JavaScript gearbeitet habe und dessen Schwächen kenne, muss ich leider sagen dass ich immer noch sehr, sehr, sehr vorsichtig arbeiten muss, wenn es um mein tägliches Brot geht. JavaScript hat ein paar sehr gute Ideen – aber trotzdem, die fehlende Sicherheit beim Entwickeln empfinde ich als sehr nachteilig. Eine Sprache sollte den Entwickler unterstützen – und nicht umgekehrt.
Ich habe im folgenden 10 Punkte aufgelistet, die mich besonders mit meiner täglichen JavaScript Arbeit beschäftigt haben und die jetzt mit Dart gelöst werden (sollen). Wegen ihnen – aber nicht nur – werde ich irgendwann zu Dart wechseln. Dabei darf man aber nicht vergessen, das Dart immer noch “in der Mache” ist, und sich somit noch einiges verändern kann. Ungefragt und jederzeit.
1. Dart kennt nur einen “falsify” Wert
In diesem Post kann man recht schnell sehen was ich meine. Die Werte: false, null, undefined, “”, 0, NaN in JavaScript gelten als “false”. Das heißt, man kann solche Dinge machen:
var a = null;
if(!a) {
// do
}
In Dart gibt es nur einen Wert der “false” ist, nämlich “false” selbst. Natürlich muss man den Code dann etwas anders schreiben:
var a = null;
if(a != null) {
// do
}
6 verschiedene Ausdrücke die “false” ergeben – das muss man erstmal wissen.
2. Dart arbeitet mit Typen, wenn man das will
JavaScript Entwickler sagen oft, dass Typen die Flexibilität reduzieren. OK, das mag wahr sein. Aber zu viel Flexibilität reduziert auch die Qualität der Software
. Manchmal will man eben mit Typen arbeiten, und Dart erlaubt es einem, wenn man es möchte. Man muss einfach nur den Typechecker anschalten, schon kann man damit loslegen.
3. Man braucht ein weiteres Framework in JS um gut mit dem DOM arbeiten zu können
In JavaScript gibt es unsere alten Freunde:
getElementsById()
getElementsByTagName()
getElementsByName()
getElementsByClassName()
querySelector()
querySelectorAll()
document.links
document.images
document.forms
document.scripts
formElement.elements
selectElement.options
Ganz schön viel. Glücklicherweise haben wir jQuery und Co, die uns aus dieser Geschichte raushelfen. Aber, sollte es heutzutage wirklich noch nötig sein ein extra Framework einzubinden, nur um mit dem DOM zu arbeiten? Eigentlich doch nicht.
Dart hat sich jQuery ansehen und daraus genau zwei Methoden abgeleitet:
elem.query('#foo');
elem.queryAll('.foo');
Besser.
4. Klassen und Interfaces
Wenn Java Entwickler mit JavaScript anfangen, versuchen sie oft JavaScript so zu programmieren, wie sie auch Java schreiben würden. Da gibt es dann Konstruktoren und klassenähnliche Elemente. Das ist aber nicht im Sinne des Erfinders und sollte anders gemacht werden: JavaScript ist eben Prototyp basiert, alles ist ein Objekt. Das ist ziemlich cool. Auf der anderen Seite kann man die Gang of Four Patterns weitgehend ausser Acht lassen und anstelle dessen ein Buch über JavaScript Patterns lesen.
Ich habe in meiner Laufbahn einige Entwickler getroffen, die bereits sehr lange Zeit benötigt haben um die gängigen Patterns zu verstehen. Nicht jeder ist ein Geek. Eine Sprache, die nicht mainstream ist, in einer mainstream-Umgebung zu verwenden führt geradewegs in das Zentrum des absoluten Chaos.
5. Vererbung
Dr. Rauschmayer erklärt in seinem ausgezeichneten Blogpost, warum JavaScript Vererbung einfach ist – und da hat er recht. Es ist wirklich einfach. Aber aufgepasst: dies ist nicht die einzige Art, wie man Vererbung durchführen kann. jQuery und das Prototype-Framework haben sogar eine extra “extend” Methode. Anstelle von dem von Dr. Rauschmayer empfohlenen __proto__ kann man das prototype Keyword verwenden (in diesem Post wird sogar von Klassen gesprochen, auch wenn es gar keine Klassen in JavaScript gibt). Natürlich kann man auch seinen
eigenen Mechanismus entwickeln und jede Eigenschaft einfach selbst kopieren.
Diese Seiten waren Suchergebnisse von Google, wenn man nach den Wörtern “javascript object extends” sucht. Es ist eigentlich ziemlich viel, was man lesen kann, obwohl es eigentlich nur ein recht einfaches Ziel zu erreichen gilt: Erweiterung.
Nicht jeder liest Dr. Rauschmayers Blog. Schade, denn das Leben wäre recht viel einfacher, falls das so wäre.
Dart kennt Klassen und kennt auch das “extends” Schlüsselwort. Ziemlich einfach.
ECMAScript 6 soll das übrigens bereinigen (Spec wird 2013 beendet werden).
6. Globaler Namespace
In JavaScript muss man aufpassen, damit man nicht einfach Zeugs in den globalen Namensraum legt. Das kann ehrlich gesagt ziemlich einfach passieren. Falls man ein “this” oder ein “var” vergisst, hat man Variablen auf globalen Level. Jedes Skript hat dann Zugriff darauf. Das ist eigentlich ziemlich schrecklich und sollte verhindert werden. Dank dem Buch von Stoyan Stefanovs namens JavaScript Patterns habe ich ein Pattern gelernt, wie man den Namensraum sauber halten kann. Jetzt geht es mir besser und ich habe wieder mehr Kontrolle über das, was ich tue. Leider brauche ich dafür ein Pattern. Das sollte eigentlich “out of the Box” geliefert werden.
In Dart entwickelt man im “Library” Scope. Das bedeutet, das Keyword “Library” verschließt ein Dart-”Paket” so, daß nur öffentliche Felder, Methoden und Klassen von außen zugänglich sind. Zusätztlich wird jedes Dart Skript als eigenes Isolate ausgeführt. Das heißt, es hat einen eigenen State und kann nicht auf den State der anderen Skripte zugreifen. Mit Dart muss man zwar immer noch über Sichtbarkeit und Bibliotheken nachdenken, aber es ist sehr viel einfacher und man braucht sicherlich auch kein Buch dafür. Anstelle davon sollte man eigentlich nur über “Separation of concerns” nachdenken müssen.
7. Dart kennt Nebenläufigkeit
Mit JavaScript sind die Dinge nicht wirklich nebenläufig. Sogar wenn man einen asynchronen Zugriff mittels jQuery durchführt befindet man sich immer noch in einem “Thread”. Mit V8 scheinen die Dinge anders zu laufen, aber genaueres weiß ich darüber nicht. Umgehen kann man dieses Problem mit HTML5 und Webworkern.
Dart kennt Isolates. Das ist damit so ähnlich wie in Erlang. Isolates können miteinander kommunizieren. Wenn ein Isolate zusammenbricht, kann es neu gestartet werden. Das ist ziemlich cool. Natürlich machen Isolates Dart auch für die serverseitige Entwicklung interessant. Und ja, ich habe von Node.js gehört. Aber das ist nicht der Punkt: Dart kann das nämlich von sich aus.
8. JavaScript kennt kein foreach.
Aber moment.
Object oder Array.prototype kann erweitert werden. Das ist natürlich nett.
Für Arrays kann man natürlich auch das machen:
for (var i = 0; i < elements.length; i++) {
// do something
}
Und man kann das für Objekte machen:
for (key in elements) {
alert(elements[key]);
}
Douglas Crockford empfiehlt dies jedoch nicht. Er sagt, die Ergebnisse sind nicht geordnet und man kann natürlich auch die Eigenschaften der prototyp-Kette sowie Funktionsnamen sehen. Die man wiederrum mit hasOwnProperty ausfiltern könnte.
Letztlich kann man natürlich auch in ein Framework wie jQuery sehen, die sowas wie forEach anbieten.
Zu guter letzt sei gesagt, das ECMAScript 5 foreach für Arrrays kennt. Zumindest alle modernen Browser unterstützen das also. Dazu gehört der Internet Explorer 8 aber offensichtlich nicht und der ist dummerweise noch im Einsatz.
In Dart:
for (element in elements) {
// do something
}
Das Leben ist damit entspannter. Damit iteriert man über eine Liste mit Elementen.
9. Seltsames initialisieren von Arrays
Das habe ich mir ausgeliehen. Man sehe sich folgendes an:
var a1 = new Array(1,2,3,4,5);
var a2 = new Array(5);
a1 ist ein Array mit 5 Elementen: [1,2,3,4,5]
a2 ist auch ein Array mit 5 Elementen: [undefined,undefined,undefined,undefined,undefined]
Dart ist da sauberer. Ein Array ist hier einfach eine Liste und hat eben ein solches Interface.
List a1 = [1,2,3,4,5];
List a2 = new List(5);
Auch hier enthält a1 fünf verscchiedene Elemente, a2 enthält nur den Platz für 5 Elemente.
Zusätzlich bekommt man Methoden wie “removeRange” oder zur Sortierung, wie man in obigen link von Seth Ladd kann.
10. undefined und null
Es gibt viel zu lernen, wenn man mit JavaScript anfängt. Darunter ist die Weisheit, dass es nicht nur null gibt – sondern auch undefined. Dabei handelt es sich um einen Typ mit nur einem Wert: undefined. Dieser kann überschrieben werden. Und den kann man quasi jederzeit bekommen, zum Beispiel wenn man return aufruft aber keinen Wert zurückgibt. Auf der verlinkten Seite kann man lesen, wie man mit undefined umgeht, wenn man sich vor einem versehentlichen Überschreiben schützen will.
In den meisten Fällen kann wohl null mit undefined ersetzt werden.
Das ist krank.
Dart kennt nur ein null.
Zusammenfassung
JavaScript hat natürlich auch seine guten Seiten. Es gibt einige sehr nette Patterns. Aber derzeit habe ich nichts gefunden, was ich nicht auch mit Dart machen könnte. Dart ist meistens eleganter und lesbarer (meiner Meinung nach). Natürlich werden einigen Hardcore-JavaScript Entwickler dem nicht zustimmen. Aber das ist OK. Man muß JavaScript mögen, wenn man damit arbeiten will. Dart dagegen ist Mainstream. Es gibt kaum böse Überraschungen.
PS: In meiner Liste habe ich die EventHandler vergessen, die in Dart sehr gelungen sind.
PPS: Außerdem habe ich die Verwirrung, die das this-Schlüsselwort in JavaScript bietet, vergessen. Vielleicht findet sich ja noch was für eine zweite Liste.