Die Geschichte von JavaScript bis ECMAScript 6

Mathias Schäfer, 9elements
PottJS Workshop Day
2016-04-02

Mathias Schäfer

  • Software-Entwickler bei 9elements
  • Germanistik und Philosophie, RUB
  • HTML, CSS und JavaScript
  • Fachartikel und Dokumentationen
  • JavaScript seit Netscape 3 und IE 4
  • Initiator von Chaplin.js
  • molily.de, @molily

9elements

  • Agentur für Software & Design
  • Webanwendungen und mobile Apps
  • Kundenarbeiten & eigene Produkte
  • Sitz im Bochumer Bermuda-Dreieck

Junior-Webentwickler∗in gesucht

</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)

Grundpfeiler der JS-Programmierung

  • Objekte sind überall
    • enthalten Daten und strukturieren Code
    • var obj = { name: 'Linda' };
  • Funktionen sind vollwertige Objekte
    • var f = function(…) {…};
    • funktionale Programmierung

Grundpfeiler der JS-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();
Tweet by @brianloveswords: “20 years ago today a programmer working for AOL named Bramdan Ich created the language Java in just 12 hours.”

20 Jahre JavaScript-Geschichte

  • Netscape Navigator 2.0, 1995
  • Scripting von HTML und Java-Applets
  • Anfang des kommerziellen, allgemein zugänglichen Webs
Netscape-Logo

Standardisierung

ECMAScript Edition 1 Cover

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

Probleme von JavaScript

JavaScript reparieren

ECMAScript Edition 5 Cover

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

  • Node.js bringt JS auf Server und Desktop
  • Derselbe Sprachkern, andere Hostumgebung
  • CommonJS-Modulsystem
  • Node Package Manager (npm)

CoffeeScript

  • 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«

Promises/A+

  • 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 Cover

ECMAScript 6 (2015)

  • Pflastert die Trampelpfade
  • Signifikante Erweiterung
  • Neue & erweiterte Kernobjekte
  • Neue, nicht abwärtskompatible Syntax

Wichtige neue ES6-Features

  1. Arrow-Funktionen
  2. Block-Scope (let und const)
  3. Deklarative Klassen
  4. 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();
Was zum Henker?!

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();
W000000t??

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

Klassen in ECMAScript 6

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

Module-Bundler

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

Der Babel-Transpiler

  • 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Ö

Stages

Quellen

Fragen? Feedback?