Die Geschichte von JavaScript bis ECMAScript 6
Mathias Schäfer, 9elements
PottJS Workshop Day
2016-04-02
Mathias Schäfer
Software-Entwickler bei 9elements
HTML, CSS und JavaScript
Fachartikel und Dokumentationen
JavaScript seit Netscape 3 und IE 4
molily.de
@molily on Mastodon
Agentur für Software & Design
Webanwendungen und mobile Apps
Kundenarbeiten & eigene Produkte
Sitz im Bochumer Bermuda-Dreieck
</eigenwerbung>
Programm
Keine vollständige Vorstellung von JavaScript und ECMAScript 6
Geschichte von JavaScript
JavaScript-Standards verstehen
ECMAScript lernen
Was ist JavaScript?
Eine interpretierte, dynamische, multiparadigmatische, universell einsetzbare Programmiersprache
Imperativ, objektbasiert, funktional…
Schwach und dynamisch typisiert
Durch C, Java, Scheme und Lisp beeinflusst
JavaScript-Übersicht
Objektbasierung: object.eigenschaft
Grundtypen: undefined, null, boolean, string, number, object…
Objekttypen: Function, RegExp, Array, Date…
Kontrollstrukturen: if, switch, for, while, for-in…
Ausdrücke: 1 + 2, objekt.methode()
Das globales Objekt (im Browser window, in Node.js global)
Objekte sind überall
enthalten Daten und strukturieren Code
var obj = { name: 'Linda' };
Funktionen sind vollwertige Objekte
var f = function(…) {…};
funktionale Programmierung
Scope: Gültigkeitsbereich von Variablen
Datenverfügbarkeit und Kapselung
Prototypenbasierte Vererbung (Delegation)
Auflösung von objekt.eigenschaft
Code-Wiederverwendung
Prototypen
Jedes Objekt hat einen Prototypen-Verweis
Der Prototyp ist ein normales Objekt
Wenn eine Eigenschaft nicht gefunden wird, wird sie beim Prototypen gesucht (Delegation)
var emma = {
doMathHomework: function () {…}
};
var alex = Object.create(emma);
alex.doHistoryHomework = function () {…};
// delegates to Emma ;)
alex.doMathHomework();
// Alex actually does the homework
alex.doHistoryHomework();
20 Jahre JavaScript-Geschichte
Netscape Navigator 2.0, 1995
Scripting von HTML und Java-Applets
Anfang des kommerziellen, allgemein zugänglichen Webs
ECMAScript
1st Edition: Juni 1997
2nd Edition: August 1998
3rd Edition: Dezember 1999
4th Edition: verworfen
5th Edition: Dezember 2009
6th Edition / 2015: Juni 2015
7th Edition / 2016: vorauss. Juni 2016
Sprachkern vs. Hostumgebung
ECMAScript standardisiert den Sprachkern
Syntax, Semantik & Ausführung der Sprache
Objekttypen & Kernobjekte
Sprachkern vs. Hostumgebung
Wie funktioniert die for-Schleife
Wie werden Variablen zu Werten aufgelöst
Wie wird ein Funktionaufruf abgearbeitet
Welche Methoden hat ein Array-Objekt
Was passiert beim Erzeugen einer Objekteigenschaft
Sprachkern vs. Hostumgebung
Verschiedene Hostumgebungen
z.B. Web-Browser, Node.js
Browser, HTML, DOM
Fenster (window, navigator, history)
HTML-Dokument (document)
User-Ereignisse (z.B. click)
Sprachkern vs. Hostumgebung
Wie kann ich ein HTML-Element ansprechen
Wie kann ich Inhalte ins Dokument schreiben
Wie kann ich auf Eingaben reagieren
Wie kann ich Daten vom Server laden / zum Server schicken
Sprachkern vs. Hostumgebung
Ausgangslage um 2005
Nützlichkeit von JavaScript wurde erkannt
JavaScript-Nutzung explodierte
Größere Webanwendungen mit JavaScript
Ausgangslage um 2005
ECMAScript 3 (1999) war gut unterstützt
Katastrophale DOM-Unterstützung
JavaScript- und Ajax-Bibliotheken: Prototype.js, Mootools, jQuery
ECMAScript 5
Korrektur von konzeptionellen Fehlern
Abwärtskompatibel soweit möglich
Vorsichtige Erweiterung der Kernobjekte
Kommerzielle Entwicklung sicherer und robuster machen
ECMAScript 5
Der Strict Mode : 'use strict';
Problematisches Verhalten deaktivieren
Programmierfehler sind schneller zu erkennen
Zugriffsrechte für Objekt und Eigenschaften
Objekte versiegeln und einfrieren
var f = function() {
'use strict';
console.log(this); // undefined
// 💥 ReferenceError:
// zahl is not defined
zahl = 1;
};
f();
Wegweisende Entwicklungen nach ES5
2008: Neue Engines entstehen (Chrome mit V8)
2009: Node.js
Modulsysteme: CommonJS, AMD
2009: CoffeeScript
2011: Promises
Node.js bringt JS auf Server und Desktop
Derselbe Sprachkern, andere Hostumgebung
CommonJS-Modulsystem
Node Package Manager (npm)
Metasprache, die nach JS kompiliert
Vereinfacht die JavaScript-Syntax
Kurzschreibweisen für Objekte, Funktionen uvm.
Deklarative Klassen
Binding von Funktionen (this)
Hält sich an die »Good Parts«
Pattern für asynchrone Programmierung
Objekt, das ein zukünftiges Ergebnis kapselt
Asynchroner Kontrollfluss (Erfolg- & Fehlerbehandlung)
Lässt sich in gewöhnlichem JS umsetzen
ECMAScript 6 (2015)
Pflastert die Trampelpfade
Signifikante Erweiterung
Neue & erweiterte Kernobjekte
Neue, nicht abwärtskompatible Syntax
Wichtige neue ES6-Features
Arrow-Funktionen
Block-Scope (let und const)
Deklarative Klassen
Modulsystem
Arrow-Funktionen
Kurzschreibweise für Funktionen
ES5: var sum = function (a, b) { return a + b; };
ES6: var sum = (a, b) => { return a + b; };
ES6: var sum = (a, b) => a + b;
ES6: var plus2 = a => a + 2;
Arrow-Funktionen
Lexikalisches this
this lässt sich aus der Umgebung erschließen
Kein this-Binding nötig und möglich
console.log(this); // Gewisser Wert
var normalFunction = function() {
console.log(this); // ggf. anderer Wert
};
var arrowFunction = () => {
console.log(this); // gleicher Wert
};
var verzögerteAusgabe = {
start: function() {
console.log('start', this);
setTimeout(() => {
// this ist dasselbe wie
// in der äußeren Funktion
this.ende();
}, 1000);
},
ende: function() {
console.log('ende', this);
}
};
verzögerteAusgabe.start();
var, let und const
var erzeugt eine Variable im Gültigkeitsbereich der aktuellen Funktion (Function Scope)
let erzeugt eine Variable im aktuellen {…}-Block (Block Scope)
const erzeugt eine Konstante im aktuellen Block
var
var ausgabe = () => {
var zahl = 1;
console.log(zahl);
};
ausgabe();
console.log(typeof zahl); // undefined
Grundregel: Lokale statt globale Variablen
let
var kleinerGauß = (n) => {
let ergebnis = 0;
for (let i = 1; i <= n; i++) { // Block
// Hier sind ergebnis und i verfügbar
ergebnis += i;
}
console.log(typeof i); // undefined
return ergebnis;
};
console.log(kleinerGauß(5)); // 15
// undefined, undefined
console.log(typeof ergebnis, typeof i);
const
const sum = (a, b) => a + b;
// 💥 TypeError: Assignment to constant variable.
sum = (a, b) => a * b;
Konstante Namen vs. konstante Werte
Bei const ist nur die Verbindung zwischen Name und Wert konstant
Objekte sind i.d.R. veränderbar (mutable)
const user = { name: 'Miffy' };
user.name = 'Nijntje'; // Funktioniert
Unveränderbare Objekte (ES5)
'use strict';
const user = { name: 'Miffy' };
Object.freeze(user);
// 💥 TypeError: Cannot assign to
// read only property 'name'
user.name = 'Nijntje';
Verwendung von var, let, const
Nach Möglichkeit const verwenden
Neuer Wert → neue Konstante
Einfacher, lesbarer Code
In Sonderfällen let
Nie mehr var verwenden
Pseudoklassen in ES5
// Konstruktorfunktion
var Cat = function(name) {
this.name = name;
};
// Prototyp
Cat.prototype.meow = function() {
console.log(this.name + ' meows.');
};
// Instanz
var kitty = new Cat('Kitty');
kitty.meow();
Klassen in ECMAScript 6
class Cat {
constructor(name) {
this.name = name;
}
meow() {
console.log(this.name + ' meows.');
}
}
var kitty = new Cat('Kitty');
kitty.meow();
Vererbung in ES5
var Animal = function(name) {
this.name = name;
};
Animal.prototype.sayHello = function() {
console.log(this.name + ' says hello!');
};
var Cat = function(name) {
Animal.call(this, name);
}
// Prototypen-Verweis aufsetzen
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.meow = function() {
console.log(this.name + ' meows.');
};
var kitty = new Cat('Kitty');
kitty.sayHello();
kitty.meow();
Vererbung in ES6
class Animal {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(this.name + ' says hello!');
}
}
class Cat extends Animal {
meow() {
console.log(this.name + ' meows.');
}
}
var kitty = new Cat('Kitty');
kitty.sayHello();
kitty.meow();
Prototypen-Kette
kitty
⬇
Cat.prototype
⬇
Animal.prototype
⬇
Object.prototype
Pro & Contra Klassen
Kurzschreibweise für verbreitetes Pattern
Macht einfache Vererbung einfach
Erlaubt keine komplexe OOP (Mehrfachvererbung, Mixins, Traits)
Pro & Contra Klassen
Objekte & Prototypen sind einfach & flexibel
Klassen sind unflexibel
»Syntaxzucker« versteckt Interna
Natives Modulsystem
Aufteilung in Module
Modul: eine Datei oder Paket
Exportieren von Werten (z.B. Funktionen)
Importieren von Werten (Abhängigkeiten)
sum.js
export default (a, b) => a + b;
program.js
import sum from './sum.js';
console.log(sum(2, 3));
math.js
export const sum = (a, b) => a + b;
export const difference = (a, b) => a - b;
export const product = (a, b) => a * b;
export const quotient = (a, b) => a / b;
program.js
import { sum, product } from './math.js';
console.log(product(sum(2, 5), 3)); // 21
Paketmanager
Node Package Manager (npm)
Bibliotheken und Frameworks nutzen
Abhängigkeiten verwalten
package.json, dependencies
import $ from 'jquery';
Module-Bundler
Code in kleinen Dateien verteilt → Module-Bundler erzeugen Builds
Abhängigkeitsbaum linearisieren
Große JS-Datei für Production
ES6 in der Praxis
Browserunterstützung
Die großen Browser werden im Jahr 2016 ES6 unterstützen
Für ältere Browser wird ES6 nach ES5 übersetzt
Framework zur Transformierung von JS-Code
Parsing → Transformationen → Ausgabe
Einzelne Transformationen: Plugins
Gruppen von Transformationen: Presets
ES6 → ES5 ist ein Preset: es2015
Babel
npm install --save-dev babel-cli
.babelrc
{ "presets": [ "es2015" ] }
Babel
./node_modules/.bin/babel script.js
--out-file output.js
In Build-Scripte einbinden (Grunt/Gulp, Rollup, Webpack, Browserify…)
Was kann Babel übersetzen?
Syntaxzucker (z.B. Klassen)
Gewisse neue Syntax (z.B. let und const)
Neue und erweiterte Kernobjekte benötigen Polyfill (z.B. Promise, Map, Set)
Babel-Polyfill basiert auf CoreJS
Babel kann mehr
ES6 → ES5
Plugins, die neue Syntax umsetzen
Zukünftige & experimentelle Features
Jedes Plugin erschafft eine neue Sprache – mit allen Vor- und Nachteilen
Weiterentwicklung von ECMAScript
Stages
0 Strawman
1 Proposal
2 Draft
3 Candidate
4 Finished → VÖ