ES6 / ES2015
and beyond …

ES6 / ES2015
and beyond …

Agenda für heute
- ECMAScript im Allgemeinen
- ES6 Features
- Wie kann ich ES6 heute nutzen
Was ist ECMAScript?
JavaScript vs ECMAScript
- JavaScript
- die Programmiersprache
- ECMAScript
-
Spezifikation des Sprachkerns
- Nicht der APIs
- Nicht die Browser und Node Spezifika
-
Spezifikation des Sprachkerns
Wer schreibt die Spezifikation?
- Nicht etwa das W3C oder WHATWG
- Sondern Ecma TC39
- genauer »Ecma International,
Technical Committee 39 - ECMAScript«
- genauer »Ecma International,
Historie und Zukunft
ECMAScript versions
- 1st Edition: Juni 1997
- 2nd Edition: August 1998
- 3rd Edition: Dezember 1999
4th Edition: verworfen- 5th Edition: Dezember 2009
- 6th Edition / 2015: Juni 2015
Näheres zur Historie:
Eine kurze Geschichte von JavaScript
Jedes Jahr eine neue Version
- ECMAScript 7 / 2016
- voraussichtlich Juni 2016
- wesentlich weniger Features als in ES6
- Array.prototype.includes
- Exponentiation Operator
- Siehe: The final feature set of ES2016
Ausblick auf ES8 / 2017 😱
- Proposals auf Stage 4 kommen in ES8
- https://github.com/tc39/ecma262
Umstieg von ES5 nach ES6
What could possibly go wrong?!?
-
100% ige Kompatibilität
- Identische Einbindung
-
Kein ES6 Mode
- automatisch ES5 'strict mode'
- ES6 striktes Superset von ES5
- keine Features entfernt
-
Häppchenweise anfangen
- benutzen was einen interessiert
Features
Könnte man aufteilen nach:
- Syntaktischer Zucker für bestehende Features
- z.B. Classes
- Neue Funktionalitäten in der standard library
- z.B. Neue Methoden für Strings und Arrays
- Komplett neue Features
- z.B. Generators, Proxies, WeakMaps
let & const
Block scoped Variablen
// Assume age is 55
if (age > 50) {
let dogAge = age * 7;
let sentence = 'You’re pretty old. In dog years you are ' + dogAge;
console.log(sentence); // → You’re pretty old. In dog years you are 385
}
console.log(sentence); // → ReferenceError: sentence is not defined
let
const company = 'Micromata';
// 42 locs later
company = 'Polyas'; // → TypeError: 'company' has already been declared
const
Aber Constants sind nicht immutable 👻
const vinnie = {
age: 0,
weight: 3.5
}
// Properties can change
vinnie.age = 1;
vinnie.weight = 12;
console.log(vinnie); // → Object {age: 1, weight: 12}
Merke!
- Verwende wenn möglichst const
- oder let
- var nur falls explizit function level scope gewünscht
Template strings
String concatenation und mehr
'single' + vs + "double" + quotes
- in JavaScript nur stylistische Geschmacksfrage
- kein Unterschied in der Interpretation
// The old way
var name = 'Hansi';
var age = 5;
var sentence = 'My cat ' + name + 'is ' + age + 'years old.';
console.log(sentence); // → My cat Hansi is 5 years old.
Bisher
// or even
var sentence = [];
sentence.push('My cat');
sentence.push(name);
sentence.push('is');
sentence.push(age);
sentence.push('years old.');
sentence = sentence.join(' ');
console.log(sentence); // → My cat Hansi is 5 years old.
// The ES6 way
const name = 'Hansi';
const age = 5;
const sentence = `My cat ${name} is ${age} years old.`;
console.log(sentence); // → My cat Hansi is 5 years old.
`backticks`
const person = {
name: 'Michael',
job: 'developer',
city: 'Kassel',
};
const markup = `
<div class="person">
<h2>
${person.name} –
<span class="job">${person.job}</span>
</h2>
<p class="city">${person.city}</p>
</div>
`;
console.log(markup);
Multi line strings
// Classic string concatenation
let age = 55;
const dogAge = age * 7;
const sentence = 'You are ' + dogAge + ' years in dog years.';
console.log(sentence); // → You’re pretty old. In dog years you are 385
// Using ES6 template literals
let age = 55;
const sentence = `You are ${age * 7} years in dog years.`;
console.log(sentence); // → You’re pretty old. In dog years you are 385
Expressions
// Use existing functions
const bill = `your total bill is ${calculateBill(11.54)} including taxes.`
Functions
const username = 'Kai';
const age = Math.floor(Math.random()*100);
function query(queryParts, ...params) {
const query = mysql.prepare(queryParts.join('?'), params);
return query.execute();
}
query`UPDATE users SET age = ${age} WHERE username = ${username}`;
// Generiert:
// query: 'UPDATE users SET age = ? WHERE username = ?'
// payload: [42, 'Kai']
Tagged template literals
Fazit
- Template literals erhöhen
- Lesbarkeit
- Wartbarkeit
- Tagged template literals sind mehr als syntaktischer Zucker
Arrow functions
Making `this` good again
Syntaktisches
// Functions in ES5
var names = ['Hans', 'Emma'];
var fullNames = names.map(function(name){
return `${name} Eichenfeld`;
});
console.log(fullNames); // ["Hans Eichenfeld", "Emma Eichenfeld"]
Introduction
// Arrow functions in ES6
var names = ['Hans', 'Emma'];
// Replace `function(name)` with `(name) =>`
var fullNames = names.map((name) => {
return `${name} Eichenfeld`;
});
console.log(fullNames); // ["Hans Eichenfeld", "Emma Eichenfeld"]
// Arrow functions in ES6
var fullNames = names.map((name) => {
return `${name} Eichenfeld`;
});
Single arguments
// Lose the parens if you prefer
var fullNames = names.map(name => {
return `${name} Eichenfeld`;
});
// Lose `return` keyword and curly braces if you prefer
var fullNames = names.map(name => `${name} Eichenfeld`);
Implicit return
Compared to ES5 1nce again
// Implicit return an object literal
var fullNames = names.map(name => ({first: name, last: 'Eichenfeld'}) );
Returning object literals
var fullNames = names.map(function(name){
return `${name} Eichenfeld`;
});
const numbered = names.map((name, index) => `${name} is No. ${index + 1}`);
Multiple arguments
setTimeout(() => { console.log('done') }, 1000);
// vs ES5 way
setTimeout(function () {
console.log('done');
}, 1000);
No arguments
this
Bei Verwendung von Arrow functions ändert sich der Wert von this nicht.
// ES5 binding of `this`
card.addEventListeneI('click', function() {
// Add closing class to start closing animation
this.classList.add('closing');
// Add closed class after 500 milliseconds
setTimeout(function(){
this.classList.add('closed'); // Cannot read property 'add' of undefined(…)
console.log(this); // Window {external: Object, chrome: Object …}
}, 500);
});
What’s `this`?
// ES5 »fix«
card.addEventListeneI('click', function() {
var self = this;
this.classList.add('closing');
setTimeout(function(){
self.classList.add('closed');
}, 500);
});
// Lexical `this` with ES6 arrow functions
card.addEventListeneI('click', function() {
// Add closing class to start closing animation
this.classList.add('closing');
// Add closed class after 500 milliseconds
setTimeout(() => {
this.classList.add('closed'); // Works \o/
}, 500);
});
Lexical scoping `this`
Promises
Asynchronität unter Kontrolle
Allgemein, Promises
- kapseln asynchrone Ereignisse
- verbergen so Komplexität vor dem Nutzer
- bieten einen Synchronisationspunkt über .then()
- verbessern Lesbarkeit von Code
- vermeiden Pyramid-of-Doom
- bieten Highlevel APIs und tiefe Integration in bestehende Methoden
-
Promise.all([promise1, promise2, ...aBunchOfPromises]);
-
Promise.race([hedgehogPromise, BunnyPromise]);
-
fetch('http://google.com').then(somehowSaveToDisk);
-
// Just for fun
const hedgehog = new Promise((resolve) => setTimeout(resolve, 500, 'hedgehog'));
const bunny = new Promise((resolve) => setTimeout(resolve, 25, 'bunny ftw'));
const competitors = [hedgehog, bunny];
Promise.race(competitors)
.then((winner) => console.log(winner));
Promise.all(competitors)
.then((list) => console.log(`All ${list.length} competitors have arrived`));
// Production usecase
const bigData = fetch('http://wikipedia.com').then(response => response.blob());
const timeout = new Promise((resolve, reject) => {
setTimeout(reject, 3000, new Error('Action took too long'));
});
Promise.race([bigData, timeout])
.then(somehowConsume)
.catch((reason) => console.error(reason));
Konkret
Promise.resolve('start')
.then((step) => new Promise((resolve) => setTimeout(resolve, 500, 1)) )
.then((step) => 2)
.then((step) => {
throw new Error(3);
})
.then((step) => 'Will not step in')
.catch(() => 'In the place to be')
.then((message) => console.log(message));
Einmal Promise, immer Promise
Default function parameters
function calculateBill (price, tax = 0.19, tip = 0.1) {
return price + (price * tax) + (price * tip);
}
// Use the defaults
console.log(calculateBill(100)); // 129
// Specify custom values
console.log(calculateBill(100, 0.13, 0.15)); // 128
// Specify one of them
console.log(calculateBill(100, undefined, 0.15)); // 134
Default values
// VS the ES5 way
function calculateBill (price, tax, tip) {
tax = tax || 0.19;
tip = tip || 0.1;
return price + (price * tax) + (price * tip);
}
// Invocation
selectEntries({ start: 0, end: -1 });
Passing object literals
// ES5 function declaration
function selectEntries(options) {
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
// […]
}
// ES6 using destructuring in parameter definitions
function selectEntries({ start=0, end=-1, step=1 }) {
// […]
}
Making that optional
// ES5: Add line A
function selectEntries(options) {
options = options || {}; // (A)
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
// […]
}
// ES6: specify {} as default value
function selectEntries({ start=0, end=-1, step=1 } = {}) {
// […]
}
Fazit
- Syntaktischer Zucker
- Macht code deutlich
- lesbarer
- kompakter
Destructuring
- Arrays und Iteratoren
- Destrukturieren von Objekten
- Emulation von Named Function Parameters
let [start, middle, end] = [1, 2, 3];
console.log({start, middle, end}); // → {start: 1, middle: 2, end: 3}
function makeIterator(obj) {
let nextIndex = 0;
const keys = Object.keys(obj);
return {
[Symbol.iterator]() {
return {
next: () => {
if (nextIndex >= keys.length) return {done: true};
const key = keys[nextIndex++];
return {value: {key, value: obj[key]}, done: false};
};
}
};
}
let [, secondTupel] = makeIterator({
x: 100,
y: 200,
z: 300,
});
console.log(secondTupel); // → {key: "y", value: 200}
Arrays und Iteratoren
let person = {name: 'Kai', age: 30};
/**
* Object destructuring
*/
let {name} = person;
console.log(name); // → Kai
/**
* Object destructuring with mapped properties
*/
const {name: boss} = person;
console.log(boss); // → Kai
/**
* Object destructuring in function parameters
*/
function drawRectangle({x: left = 0, y: top = 0, width = 100, height = width} = {}) {
console.log('Somehow draw', {left, top, width, height});
}
// → "Somehow draw", {left: 0, top: 75, width: 100, height: 100}
drawRectangle({y: 75});
Objekte
For the ...rest of us
Rest Parameter
- Fangen alle (ggf. übrigen) Parameter
- Ist immer ein echtes Array
-
rest instanceof Array === true
-
- Kann nur als letztes Argument auftauchen
/**
* No brainer
*/
function join(...strings) {
return strings.join(' ');
}
console.log(join('With', 'great', 'power')); // → "With great power"
/**
* Semi brainer
*/
let [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log({a, b, rest}); // → {a: 1, b: 2, rest: [3, 4, 5]}
/**
* Brain cancer
*/
let [start, ...tail] = (function *() {for (let i = 0; i <= 100; i++) yield i})();
// → {start: 0, tail: [1, 2, 3, 4, 5, 6, 7, 8, 9, […], 100]}
console.log({start, tail});
Brain massage
let set = new Set([4, 5, 6, 5, 4]);
let biggerSet = [...set, 7 ,8, 9];
console.log(biggerSet); // -> [4, 5, 6, 7, 8, 9]
let alphabet = 'abcdefghijklmnopqrstuvwxyz';
let hugeSet = [0, 1, 2, 3].concat(biggerSet, ...alphabet);
console.log(hugeSet); // -> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", […], "z"];
obj.method(...args) === obj.method.apply(obj, args);
...spread als Inverse zu ...rest
Classes
Syntaktischer Zucker für protype based inheritance
// ES5
function Person(name) {
this.name = name;
}
Person.prototype.describe = function () {
return 'Person called '+this.name;
};
var person = new Person("Michael");
console.log(person.describe()); // "Person called Michael"
Constructor functions
// ES6
class Person {
constructor(name) {
this.name = name;
}
describe() {
return 'Person called '+this.name;
}
}
let person = new Person("Michael");
console.log(person.describe()); // "Person called Michael"
// ES5
function Employee(name, title) {
Person.call(this, name); // super(name)
this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
return Person.prototype.describe.call(this) // super.describe()
+ ' (' + this.title + ')';
};
Inheritance – Derived Classes
// ES6
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return super.describe() + ' (' + this.title + ')';
}
}
Neue OOP Features
neben classes
Object literals
Neue Features === syntaktischer Zucker
// We have some data
const name = 'Hansi';
const breed = 'Highlander';
const age = 5;
Property value shorthands
// and we need it in an object
const cat = {
name: name,
breed: breed,
age: age
}
// With ES6 we can use property value shorthands
const cat = {
name,
breed,
age,
siblings: ['Emma', 'Minnie', 'Maxi']
}
// ES5 way to define methods
var modal = {
open: function(content) {
// open
},
close: function() {
// close
}
}
Method definitions
// The ES6 way
var modal = {
open(content) {
// open
},
close() {
// close
}
}
Neue Methoden
von object
/**
* Object.assign(target, source_1, source_2, ···)
* Merges the sources into the target
*/
const obj = { foo: 123 };
Object.assign(obj, { bar: true });
console.log(JSON.stringify(obj)); // {"foo":123,"bar":true}
Object.assign()
Object.assign()
// Another use case is adding methods to objects
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
// […]
},
anotherMethod() {
// […]
}
});
// vs ES5 way
SomeClass.prototype.someMethod = function (arg1, arg2) {
// […]
};
SomeClass.prototype.anotherMethod = function () {
// […]
};
Object.assign()
// Use case: cloning objects
const myObject = {
foo: 123,
bar: true
}
function clone(original) {
return Object.assign({}, original);
}
const myOtherObject = clone(myObject);
delete myObject.foo;
console.log(JSON.stringify(myObject)); // {"bar":true}
console.log(JSON.stringify(myOtherObject)); // {"foo":123,"bar":true}
Object.is()
// Will make JavaScript less weird
NaN === NaN; // false
Object.is(Nan, NaN); // true
0 === -0; // true
Object.is(0, -0); // false
// Everything else is compared as with strict equality operator
5 == '5' // true
5 === '5' // false
Object.is(5, '5') // false
Modules
ES6 bringt ein Module-System 🎉
Zumindest theoretisch 🙈
… also, zur Theorie
Wofür Module?
- Wartbarkeit
- Das Problem mit dem globalen Scope
- Pollution sorgt für Konfliktpotential
Lösungsansätze in ES5
- Design Patterns mit Hausmitteln
- Asynchronous Module Definition (AMD)
- CommonJS
// moduleFoo.js
// Namespace
var myNamespace = window.myNamespace || {};
// Module (Revealing Module Pattern)
myNamespace.moduleFoo = (function ($) {
'use strict';
var yourPublicMethod = function (message) {
console.info(message);
};
var _yourPrivateMethod = function (message) {
console.info(message);
};
document.addEventListener('DOMContentLoaded', function () {
_yourPrivateMethod('Hi Private.');
});
// Return functions to make them accessible from outside.
return {
yourPublicMethod: yourPublicMethod
};
})();
Modules in ES5 mit Hausmitteln
// moduleBar.js
// Namespace
var myNamespace = window.myNamespace || {};
// Module (Revealing Module Pattern)
myNamespace.moduleFoo = (function ($) {
'use strict';
var _anotherPrivateMethod = function (message) {
console.info(message);
};
document.addEventListener('DOMContentLoaded', function () {
_anotherPrivateMethod('Hi Private.');
myNamespace.moduleFoo.yourPublicMethod('Hi public.');
});
})();
ES6 modules
- Wie CommonJS Module
- Kein globaler scope
- Weniger boilerplate🏼
// lib.js
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//foo.js
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
Multiple exports
//myFunc.js
export default function () { […] } // no semicolon!
// main1.js
import myFunc from 'myFunc';
myFunc();
Single exports
ES6 modules verwenden
- 💚 Module syntax ist in ES6 specs definiert
- 💛 Die module loader specs sind 2015 aus ES6 raus
- Werden von der WHATWG weiterentwickelt
- 💔 Modules bis jetzt in keiner JS Engine implementiert
Module bundler 💝
- lassen uns die ES6 module Syntax heute nutzen
- transpilieren den code nach ES5
- Große Auswahl an Tools wie:
- browserify, webpack, jspm/SystemJS
Wo kann man ES6 nutzen?

Browsersupport
Browser | ES6 Implementierung |
---|---|
Microsoft Edge 13 | 79% |
Internet Explorer 11 | 15% |
FireFox 46 | 90% |
Chrome 50 | 93% |
Safari 9 | 53% |
Stand: 11. Mai 2016
Node.js Support
Version | ES6 Implementierung |
---|---|
v6.1.0 | 96% |
v5.x.x | 58% |
v4.x.x | 47% |
v0.12.14 | 30% |
Stand: 11. Mai 2016
Quelle: http://node.green
😐
Transpiling to the rescue
ES6 ➡ ES5
Transpilersupport
Transpiler | ES6 Implementierung |
---|---|
Closure compiler | 42% |
Traceur | 58% |
TypeScript | 60% |
Babel | 74% |
Stand: 11. Mai 2016
Wie kann ich Babel nutzen?
- CLI
- Build tool
- Make, Broccoli, Brunch, Grunt, Gulp, …
- Module bundler
- Browserify, Rollup, Webpack
Siehe: babeljs.io/docs/setup
Babel ausprobieren

Siehe: babeljs.io/repl
Teaser
ES6 in Bootstrap Kickstart
- Nächstes Major Release steht kurz bevor
- Wird folgendes mitbringen:
- ES6 transpiling via Babel
- Module bundling via browserify
- Package management ausschließlich via npm
- Automatisierte security checks (für dependencies)
- etc …
- Siehe vor allem PR von Rene 😘
Links
- Einstieg
- Interactives lernen
- Transpiling mit Babel
- Support tables
Das war’s
Fragen, gerne und jederzeit.

ES6 / ES2015
By Michael Kühnel
ES6 / ES2015
– ECMAScript im Allgemeinen – ES6 Features – Wie kann ich ES6 heute nutzen
- 1,519
Loading comments...