Was ist ES6+?
Im Juni 2015 erhielt JavaScript sein bisher größtes Update. ECMAScript 2015, besser bekannt als ES6, führte Block-Scoping, Arrow Functions, Klassen, Module, Promises und vieles mehr ein. Das Komitee, welches die Sprache pflegt, verpflichtete sich darauf, fortan jedes Jahr eine neue Edition zu veröffentlichen. „ES6+“ ist so zur Kurzbezeichnung für diese gesamte moderne Ära geworden.
Du musst nicht jedes einzelne Feature lernen. Eine Handvoll davon macht den Großteil des täglichen Codes aus – und genau diese werden in diesem Guide behandelt. Das gemeinsame Thema all dieser Neuerungen ist simpel: Drücke dich präziser aus, aber mit weniger unnötigem Boilerplate.
let und const
Das älteste Feature ist zugleich das wichtigste. var ist function-scoped und wird auf eine Weise gehoisted, die viele überrascht. let und const sind block-scoped, sie existieren also nur innerhalb des nächstgelegenen { }.
// scope.js
if (true) {
let message = "inside";
const limit = 10;
}
// message and limit are not defined out here
const verhindert die Neuzuweisung der Bindung, wodurch deine Absicht deutlich wird: dieser Name wird nicht auf etwas anderes verweisen. Es friert den Wert jedoch nicht ein, sodass ein const Array weiterhin mutiert werden kann. Nutze standardmäßig const, let wenn eine Neuzuweisung tatsächlich nötig ist, und betrachte var als Teil der Historie.
Arrow Functions
Arrow Functions bieten eine kürzere Syntax mit einem wichtigen verhaltensbezogenen Unterschied: Sie besitzen kein eigenes this. Sie erben this aus dem umschließenden Scope, was bei Callbacks fast immer das gewünschte Verhalten ist.
// arrows.js
const add = (a, b) => a + b;
const square = (n) => {
return n * n;
};
const names = ["Ada", "Grace", "Linus"];
const upper = names.map((name) => name.toUpperCase());
Wenn der Body aus einem einzigen Ausdruck besteht, können die geschweiften Klammern und return weggelassen werden. Klammern um einen einzelnen Parameter sind optional. Da Arrow Functions this erfassen, eignen sie sich ideal für Event-Handler und Array-Methoden, sind jedoch weniger geeignet für Objekt-Methoden, die ein eigenes this benötigen.
Template-Literals
Backticks ermöglichen die Erstellung von Strings, die sich über mehrere Zeilen erstrecken und Ausdrücke mittels ${ } interpolieren.
// message.js
const name = "Ada";
const role = "engineer";
const greeting = `Hello, ${name}!
You are logged in as a ${role}.`;
Template-Literals unterstützen zudem Tagged Templates. Hierbei erhält eine Funktion die literalen Teile und die interpolierten Werte separat. Dieser Mechanismus bildet die Grundlage für viele Templating- und Styling-Libraries.
Destructuring
Destructuring entpackt Werte aus Arrays und Objekten in Variablen, wodurch viele repetitive Zugriffe auf Eigenschaften entfallen.
// destructure.js
const user = { name: "Ada", age: 36, city: "London" };
const { name, age, city = "Unknown" } = user;
const coords = [51.5, -0.12];
const [lat, lng] = coords;
function greet({ name }) {
return `Hello, ${name}`;
}
Du kannst beim Destructuring Variablen umbenennen (const { name: userName } = user), Standardwerte angeben und direkt in der Parameterliste einer Funktion destrukturieren – ein Muster, das ständig bei React props und Konfigurationsobjekten verwendet wird.
Spread und Rest
Die gleichen drei Punkte erfüllen je nach Position zwei komplementäre Aufgaben.
// spread.js
const a = [1, 2, 3];
const b = [4, 5];
const combined = [...a, ...b]; // spread: expand
const copy = { ...user, age: 37 }; // shallow clone + override
function sum(...numbers) { // rest: collect
return numbers.reduce((t, n) => t + n, 0);
}
Spread kopiert Werte in ein neues Array oder Objekt, was die Grundlage für immutable Updates bildet. Rest fasst verbleibende Argumente oder Elemente in einem einzigen Array zusammen. Zusammen machen sie die Arbeit mit Collections wesentlich angenehmer.
Standardparameter und Shorthand
Funktionen können Standardwerte deklarieren, und Objekt-Literale können die Shorthand-Schreibweise nutzen, wenn der Eigenschaftsname mit einer Variable übereinstimmt.
// config.js
function connect({ host = "localhost", port = 8080 } = {}) {
return `${host}:${port}`;
}
const name = "Ada";
const user = { name, greet() { return `Hi, ${this.name}`; } };
Standardwerte werden nur dann ausgewertet, wenn das Argument undefined ist, was in der Regel das gewünschte Verhalten ist. Shorthand-Properties und -Methoden reduzieren das Rauschen in Code, der stark auf Objekten basiert.
Optional Chaining und Nullish Coalescing
Diese beiden Operatoren, die 2020 eingeführt wurden, haben unzählige defensive Prüfungen überflüssig gemacht.
// safe.js
const city = user?.address?.city;
const name = input ?? "anonymous";
user?.profile?.onLogin?.();
?. führt einen Short-Circuit zu undefined aus, wenn der Wert auf der linken Seite null oder undefined ist. ?? bietet einen Fallback nur dann, wenn die linke Seite null oder undefined ist – im Gegensatz zu || werden 0, "" oder false nicht als fehlend behandelt.
Array-Methoden
Der Array-Prototyp ist vollgepackt mit Methoden, die die Absicht beschreiben, anstatt die Loop-Mechanik in den Vordergrund zu stellen.
// arrays.js
const products = [
{ name: "Keyboard", price: 80, inStock: true },
{ name: "Mouse", price: 40, inStock: false },
{ name: "Cable", price: 10, inStock: true },
];
const names = products.map((p) => p.name);
const cheap = products.filter((p) => p.price < 50);
const total = products.reduce((sum, p) => sum + p.price, 0);
const available = products.some((p) => p.inStock);
const allCheap = products.every((p) => p.price < 100);
const mouse = products.find((p) => p.name === "Mouse");
map transformiert, filter selektiert, reduce reduziert eine Liste auf einen einzelnen Wert, find gibt den ersten Treffer zurück und some/every prüfen eine Bedingung. Sie lassen sich chainen, mutieren das ursprüngliche Array nicht und lesen sich wie eine Beschreibung dessen, was man erreichen möchte.
Module
ES-Module ermöglichen es, Code auf mehrere Dateien aufzuteilen und nur das zu teilen, was Sie explizit auswählen.
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export default function subtract(a, b) {
return a - b;
}
// app.js
import subtract, { add, PI } from "./math.js";
Named Exports können pro Datei mehrfach vorkommen und werden über ihren Namen importiert. Ein Default Export ist ein einzelner Hauptwert. Module haben ihren eigenen Scope, werden nur einmal ausgewertet und ermöglichen es Bundlern, ungenutzten Code mittels Tree-Shaking zu entfernen.
Klassen
Klassen bieten eine klare Syntax für objektorientierten Code, die auf dem bestehenden Prototyp-System von JavaScript aufbaut.
// user.js
class User {
#secret = "hidden"; // private field
constructor(name) {
this.name = name;
}
get greeting() {
return `Hello, ${this.name}`;
}
static create(name) {
return new User(name);
}
}
class Admin extends User {
constructor(name) {
super(name);
this.role = "admin";
}
}
extends und super steuern die Vererbung, static definiert Methoden direkt an der Klasse und # kennzeichnet wirklich private Felder. Unter der Haube handelt es sich immer noch um Prototypen, aber die Syntax ist wesentlich einfacher zu lesen.
Weitere nützliche Features
- Map und Set für Key-Value-Collections und eindeutige Werte, die für diese Zwecke eine bessere Semantik bieten als einfache Objekte und Arrays.
- for…of zum Iterieren über Arrays, Strings, Maps, Sets und jedes andere Iterable.
- Exponentiation mit
**, sodass2 ** 10anstelle vonMath.pow(2, 10)verwendet wird. - Iteratoren und Generatoren für Lazy Sequences, benutzerdefinierte Iterationen und pausierbare Funktionen.
- Object.entries / fromEntries zur Konvertierung zwischen Objekten und Arrays von Paaren.
Best Practices
- Standardmäßig
constverwenden;letnur bei Neu-Zuweisungen nutzen. - Arrow Functions für Callbacks bevorzugen, reguläre Funktionen für Methoden, die
thisbenötigen. - Destructuring in den Parametern nutzen, um die erforderliche Struktur explizit zu machen.
- Den Spread-Operator für immutable Updates verwenden, anstatt gemeinsam genutzte Daten zu mutieren.
- Auf
?.und??zurückgreifen, bevor verschachtelte Guards geschrieben werden. - Bei der Transformation von Daten Array-Methoden gegenüber handgeschriebenen Schleifen bevorzugen.
- Module klein halten und nur die minimal notwendige Oberfläche exportieren.
Häufige Fehler
- Die Annahme, dass
constein Objekt unveränderlich (immutable) macht – es verhindert lediglich die Neuzuweisung (rebinding). - Die Verwendung einer Arrow-Function als Objektmethode, wodurch der Bezug auf
thisverloren geht. - Die Verwendung von
||für Standardwerte, wenn0oder""gültige Werte sind; verwenden Sie stattdessen??. - Das Spread-Operating nur eine Ebene tief und die Erwartung eines Deep Clones.
- Das Vermischen von
requireundimportim selben Modulsystem, ohne die Interoperabilität zu verstehen. - Das Verketten von zu vielen Array-Methoden zu einer unlesbaren Pipeline.
Wie geht es weiter?
Die moderne Syntax ist das Vokabular; das DOM und asynchrones JavaScript sind die Bereiche, in denen du dieses Wissen anwendest. Sobald sich Promises und Module natürlich anfühlen, verwandelt die Fetch API diese Fähigkeiten in echte Anwendungen.