x

Einloggen

Hast du noch keinen Account? Jetzt registrieren!

JavaScript 1.8

Wenn du die Entwicklung von JavaScript 1.8 nicht verfolgen konntest, hier nun ein kleiner Überblick, was bist jetzt in den neuesten Firefox 3 Nightlies integriert wurde.

Bis jetzt wurden drei Hauptelemente eingebaut und ein paar weitere sollen folgen. Im Wesentlichen wird diese Version recht 'leicht' sein, hauptsächlich um die aktuelle Javascript-Version an die gewünschten Eigenschaften von JaveScript 2 anzunähern.

Expression Closures
Dieses Element wurde gerade erst integriert und wird sicher bei Freunden der funktionalen Programmierung gut ankommen. Tatsächlich ist diese Neuerung nichts weiter als eine Kurzschrift zum Schreiben einfacher Funktionen, vergleichbar zu einer normalen Lambda-Notation.

Vergleiche beispielsweise die folgenden Lambda-Notation einiger Programmiersprachen mit JavaScript 1.8.

Python:
lambda x: x * x

Smalltalk:
[ :x | x * x ]

JavaScript 1.8:
function(x) x * x

(Als Referenz) JavaScript 1.7 und älter:
function(x) { return x * x; }

Ich glaube meine Lieblingsanwendung für diese Kurzschrift sind wahrscheinlich bindende Event-Listeners, wie der folgende:
document.addEventListener("click", function() false, true);

Oder um diese Notation mit einigen der Array-Funktionen von JavaScript 1.6 zu kombinieren:
elems.some(function(elem) elem.type == "text");

Damit kannst du ausgesprochen eleganten JS/DOM-Code erzeugen.

Generator Expressions
Dies ist ein anderes Element, das gerade erst eingebaut wurde. Im Gegensatz zu vorherigen Neuerung beinhaltet diese etwas mehr Funktionalität, da es eine Reihe von Konzepten umfasst. Insbesondere muss man sich dafür mit den meisten Elemente von JavaScript 1.7 besonders Iteratoren, Generatoren und Array Comprehension auskennen. Dieses Element ist an die Generator Expressions in Python angelehnt.

Im Ticket dieses Elements hat Brendan einen eleganten, funktionellen Sudoko-Löser eingestellt, der die neue Syntax nutzt. Dieses Demo basiert auf einem ähnlichen Programm, das in Python geschrieben wurde, um die dortigen Generator Expressions zu demonstrieren.

Um diese Element besser zu verstehen, betrachten wir uns mal eine Zeile des JavaScript 1.8 Codes vom Sudoko-Löser etwas näher.
dict([s, [u for (u in unitlist) if (u.contains(s))]] for (s in squares))

Diese Zeile nutzt die dict()-Funktion, die 2xN-Matrix in ein Key-Value-Paar-Objekt umwandelt. Der Code sieht wie folgt aus:
function dict(A) {    
    let d = {}    
    for (let e in A)        
        d[e[0]] = e[1]    
    return d
}

Betrachten wir diese Programmzeile mal Stück für Stück.
[u for (u in unitlist) if (u.contains(s))]

Der erste Teil ist ein Beispiel für eine Array Comprehension aus JavaScript 1.7. Insbesondere iterieren wir über 'unitlist' und bauen es zu einem Array von Schlüsseln (ausgenommen Schlüssel, die kein 's' enthalten) aus.
[s, ...] for (s in squares)

Der zweite Teil ist ein weiteres Beispiel für Array Comprehension. Auf den ersten Blick könnte es auch ein anderes Element aus JavaScript 1.7, Destructuring Assignment, sein, das ist aber nicht der Fall. Von einem normalen Destructuring Assignment spricht man nur dann, wenn du einen Wert zuweist, jedoch erstellst du in dieser Situation lediglich einen Array-Wert mit Array Comprehension. Diese neuen 2-Einheiten Arrays werden dann zurück in die dict-Funktion gepackt.
dict([s, ...] for (s in squares))

Und hier beginnt die Zauberei … In JavaScript 1.7 konntest du die dict()-Funktion nicht so aufrufen:
dict([[s, ...] for (s in squares)])

Beachte die zusätzliche, ausdrückliche Nutzung von Array Comprehension. Das Problem mit dieser zusätzlichen Comprehension ist, dass diese beim ersten Auftreten komplett durchlaufen werden muss, um das vollständige Array aufzubauen (das dann in ein 'dictionary' umgewandelt wird). Jedoch, macht das Fehlen von zusätzlichen [...] dies zu einer Generator Expression. Damit entspricht diese Zeile in JavaScript 1.8 der folgenden in JavaScript 1.7:
dict((function(){ for (s in squares) yield [s, ...] ; })())

Wie du sehen wirst, baut die Generator Expression das entstehende Array langsam auf (lazy-build) und behandelt es als einen Generator – d.h. die bestimmten Werte werden erst dann generiert, sobald diese ausdrücklich von der dict()-Funktion benötigt werden (damit sind weniger Loops nötig und die Gesamtleistung verbessert).

Hier ein weiteres Beispiel für eine Generator Expression
// Erstellt einen Generator, der über einen Objektwert iteriert
function val_iter(obj) {    
    return (obj[x] for (x in obj));
}

// Iteriert mittels einem Objektschlüssel (key)
for ( let key in obj ) { ... }

// Iteriert mittels einem Objektwert
for ( let value in val_iter(obj) ) { ... }

Natürlich könnte die val_iter()-Funktion mit JavaScript 1.7 jetzt mit 'yield' ausgedrückt werden:
function val_iter(obj) {    
    for (let x in obj)        
        yield obj[x];
}

Höchstwahrscheinlich eignen sich Generator Expressions am besten für Speicher-/CPU-hungrige Programme (wie dem Sudoku-Löser), da Anwendungen jetzt Ergebnisse erhalten können, wenn sie diese benötigen und so nicht alle im Voraus geladen werden müssen.
    
Spass mit Iteratoren
Nur so nebenbei, ich habe in letzter Zeit ein wenig mit Iteratoren/Generatoren rumgespielt. Dabei hatte ich besonders Interesse an einer Funktion. Ich suchte nach einer einfachen Lösung, um über eine Reihe von Ziffern (z.B. 0 – 9) zu iterieren. Mit ein wenig Geduld, kannst du der Sprache diese Funktionalität folgendermassen beibringen:    
    
// Fügt einen Iterator zu allen Ziffern                         
Number.prototype.__iterator__ = function() {        
    for ( let i = 0; i < this; i++ )             
        yield i;    
};

// Gibt drei Alarme wieder    
for ( let i in 3 ) alert( i );

// Erstellt einen 100-Einheiten Array, mit Nullen    
[ 0 for ( i in 100 ) ]

// Erstellt eine 10x10 Einheitsmatrix    
[[ i == j ? 1 : 0 for ( i in 10 ) ] for ( j in 10 )]

Dies ist für dich vielleicht ein alter Hut, aber mir hat es wirklich was gebracht.

Array Reduce
Das letzte Element, das kürzlich hinzugefügt wurde, ist die fehlende Array.reduce/Array.prototype.reduce-Funktion von JavaScript 1.6 Array Extras.

Du kannst einen Array Reduce folgendermassen aufrufen:
someArray.reduce( fn [, initial] );

mit einem Funktionsaufruf wie diesem:
someArray.reduce(function(lastValue, curValue){  
  return lastValue + curValue;
});

Das "lastValue"-Argument ist der Rückgabewert (return value) des letzten Aufrufs der Reduce-Callback-Funktion. Das erste Mal, dass der Callback aufgerufen wird, ist es ein "lastValue" aus dem ersten Element im Array (oder ein Anfangswert, wenn du diesen im Aufruf der Reduce-Funktion definiert hast) und ein "curValue" aus dem zweiten Element im Array.

So, wenn du also die Ziffern 0 bis 99 addieren möchtest, könnte das (mit JavaScript 1.8 und dem Zahleniterator von oben) wie folgt aussehen:
[x for ( x in 100 )].reduce(function(a,b) a+b);

Schick!
Du kannst die Reduce-Funktion für Sachen wie "ein Set von DOM-Nodes in einen Array zu verschmelzen" anwenden. Und das geht so:
nodes.reduce(function(a,b) a.concat(b.childNodes), []);

Versuche es einfach selber
Alle von mir beschriebenen Elemente sind im letzten Nighty von Firefox 3 integriert, wenn du also selber mal damit rumspielen möchtest — Dann los!     
  1. Nightly von Firefox 3 herunterladen    
  2. Erstelle eine Seite mit dem folgenden Script Tag (gerade erst erschienen):    
<script type="application/javascript;version=1.8"> ... your code ... 
</script>

Und dann der letzte Schritt – Geniessen!
303 Mal gelesen
+2
30. Mär 2011, 16:53

Kommentare

(0)
RSS

Kommentieren

Fett Kursiv Unterstrichen Durchgestrichen   Link Zitieren Code
Ich bin mit den Nutzungsbedingungen einverstanden.
Zukünftige Kommentare zu diesem Beitrag abonnieren (abbestellbar).
 
Bitte klicke jetzt auf den Bestätigungslink in deiner E-Mail.