Zum Hauptinhalt springen

9 Posts getaggt mit "ES2019"

Alle Tags anzeigen

Subsume JSON a.k.a. JSON ⊂ ECMAScript

· 6 Minuten Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Mit dem JSON ⊂ ECMAScript Vorschlag wird JSON zu einer syntaktischen Teilmenge von ECMAScript. Wenn Sie überrascht sind, dass dies nicht bereits der Fall war, sind Sie nicht allein!

Das alte ES2018-Verhalten

In ES2018 konnten ECMAScript-Stringliterale keine unescaped U+2028 LINE SEPARATOR und U+2029 PARAGRAPH SEPARATOR Zeichen enthalten, da sie selbst in diesem Kontext als Zeilenabschlusszeichen betrachtet wurden:

// Ein String, der ein rohes U+2028-Zeichen enthält.
const LS = '
';
// → ES2018: SyntaxError

// Ein String, der ein rohes U+2029-Zeichen enthält, erzeugt durch `eval`:
const PS = eval('"\u2029"');
// → ES2018: SyntaxError

Dies ist problematisch, weil JSON-Strings diese Zeichen enthalten können. Daher mussten Entwickler spezialisierte Nachbearbeitungslogik implementieren, wenn sie gültiges JSON in ECMAScript-Programme einbetten wollten, um mit diesen Zeichen umzugehen. Ohne solche Logik hätte der Code subtile Bugs oder sogar Sicherheitsprobleme enthalten können!

Stabile `Array.prototype.sort`

· 3 Minuten Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Angenommen, Sie haben ein Array von Hunden, wobei jeder Hund einen Namen und eine Bewertung hat. (Falls dies wie ein seltsames Beispiel klingt, sollten Sie wissen, dass es ein Twitter-Konto gibt, das sich genau darauf spezialisiert hat… Fragen Sie nicht!)

// Beachten Sie, dass das Array nach `name` alphabetisch vorsortiert ist.
const doggos = [
{ name: 'Abby', rating: 12 },
{ name: 'Bandit', rating: 13 },
{ name: 'Choco', rating: 14 },
{ name: 'Daisy', rating: 12 },
{ name: 'Elmo', rating: 12 },
{ name: 'Falco', rating: 13 },
{ name: 'Ghost', rating: 14 },
];
// Sortieren Sie die Hunde nach `rating` in absteigender Reihenfolge.
// (Dies aktualisiert `doggos` direkt.)
doggos.sort((a, b) => b.rating - a.rating);

`Symbol.prototype.description`

· Eine Minute Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JavaScript-Symbols können bei ihrer Erstellung eine Beschreibung erhalten:

const symbol = Symbol('foo');
// ^^^^^

Bisher war die einzige Möglichkeit, programmgesteuert auf diese Beschreibung zuzugreifen, indirekt über Symbol.prototype.toString():

const symbol = Symbol('foo');
// ^^^^^
symbol.toString();
// → 'Symbol(foo)'
// ^^^
symbol.toString().slice(7, -1); // 🤔
// → 'foo'

Der Code wirkt jedoch etwas magisch, ist nicht sehr selbsterklärend und verletzt das Prinzip „Absicht ausdrücken, nicht Implementierung“. Die obige Technik erlaubt es außerdem nicht, zwischen einem Symbol ohne Beschreibung (d.h. Symbol()) und einem Symbol mit leerem String als Beschreibung (d.h. Symbol('')) zu unterscheiden.

`Object.fromEntries`

· 4 Minuten Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias)), JavaScript-Zauberer

Object.fromEntries ist eine nützliche Ergänzung zur eingebauten JavaScript-Bibliothek. Bevor erklärt wird, was es tut, hilft es, die bereits vorhandene API Object.entries zu verstehen.

Object.entries

Die Object.entries-API existiert schon seit einiger Zeit.

Für jedes Schlüssel-Wert-Paar in einem Objekt liefert Object.entries ein Array, bei dem das erste Element der Schlüssel und das zweite Element der Wert ist.

Object.entries ist besonders nützlich in Kombination mit for-of, da es ermöglicht, sehr elegant über alle Schlüssel-Wert-Paare in einem Objekt zu iterieren:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

for (const [key, value] of entries) {
console.log(`Der Wert von ${key} ist ${value}.`);
}
// Ausgabe:
// Der Wert von x ist 42.
// Der Wert von y ist 50.

Leider gibt es keinen einfachen Weg, um aus dem Ergebnis von entries wieder ein äquivalentes Objekt zu erzeugen… bis jetzt!

Object.fromEntries

Die neue API Object.fromEntries führt das Umkehrverfahren von Object.entries durch. Dies erleichtert die Rekonstruktion eines Objekts basierend auf seinen Einträgen:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

const result = Object.fromEntries(entries);
// → { x: 42, y: 50 }

Ein üblicher Anwendungsfall ist das Transformieren von Objekten. Dies können Sie jetzt tun, indem Sie über deren Einträge iterieren und dann Methoden für Arrays verwenden, die Ihnen möglicherweise schon bekannt sind:

const object = { x: 42, y: 50, abc: 9001 };
const result = Object.fromEntries(
Object.entries(object)
.filter(([ key, value ]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2 ])
);
// → { x: 84, y: 100 }

In diesem Beispiel filtern wir mit filter das Objekt, um nur Schlüssel der Länge 1 zu erhalten, das heißt, nur die Schlüssel x und y, nicht jedoch den Schlüssel abc. Wir verwenden dann map, um über die verbleibenden Einträge zu iterieren und ein aktualisiertes Schlüssel-Wert-Paar für jeden zurückzugeben. In diesem Beispiel verdoppeln wir jeden Wert, indem wir ihn mit 2 multiplizieren. Das Endergebnis ist ein neues Objekt mit nur den Eigenschaften x und y und den neuen Werten.

`Array.prototype.flat` und `Array.prototype.flatMap`

· 2 Minuten Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Array.prototype.flat

Das Array in diesem Beispiel ist mehrere Ebenen tief: Es enthält ein Array, das wiederum ein weiteres Array enthält.

const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ äußeres Array
// ^^^^^^^^ inneres Array
// ^^^ innerstes Array

Array#flat gibt eine reduzierte Version eines gegebenen Arrays zurück.

array.flat();
// → [1, 2, [3]]

// …entspricht folgendem:
array.flat(1);
// → [1, 2, [3]]

Die Standardtiefe ist 1, aber Sie können jede Zahl übergeben, um rekursiv bis zu dieser Tiefe zu reduzieren. Um rekursiv zu reduzieren, bis das Ergebnis keine verschachtelten Arrays mehr enthält, geben wir Infinity weiter.

// Rekursiv reduzieren, bis das Array keine verschachtelten Arrays mehr enthält:
array.flat(Infinity);
// → [1, 2, 3]

Warum heißt diese Methode Array.prototype.flat und nicht Array.prototype.flatten? Lesen Sie unseren Bericht zu #SmooshGate, um es herauszufinden!

Array.prototype.flatMap

Hier ist ein weiteres Beispiel. Wir haben eine Funktion duplicate, die einen Wert nimmt und ein Array zurückgibt, das diesen Wert zweimal enthält. Wenn wir duplicate auf jeden Wert in einem Array anwenden, erhalten wir ein verschachteltes Array.

const duplicate = (x) => [x, x];

[2, 3, 4].map(duplicate);
// → [[2, 2], [3, 3], [4, 4]]

Sie können dann flat auf das Ergebnis aufrufen, um das Array zu reduzieren:

[2, 3, 4].map(duplicate).flat(); // 🐌
// → [2, 2, 3, 3, 4, 4]

Da dieses Muster in der funktionalen Programmierung so häufig vorkommt, gibt es jetzt eine eigene Methode flatMap dafür.

[2, 3, 4].flatMap(duplicate); // 🚀
// → [2, 2, 3, 3, 4, 4]

flatMap ist ein wenig effizienter, als map gefolgt von einem separaten flat zu verwenden.

Interessiert an Anwendungsfällen für flatMap? Schauen Sie sich Axel Rauschmayers Erklärung an.

Unterstützung für Array#{flat,flatMap}

Gut geformtes `JSON.stringify`

· Eine Minute Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JSON.stringify wurde zuvor so spezifiziert, dass es schlecht geformte Unicode-Zeichenketten zurückgibt, wenn die Eingabe einsame Surrogate enthält:

JSON.stringify('\uD800');
// → '"�"'

Der Vorschlag „Gut geformtes JSON.stringify ändert JSON.stringify so, dass es Escape-Sequenzen für einsame Surrogate ausgibt, wodurch seine Ausgabe gültiges Unicode wird (und in UTF-8 darstellbar ist):

Optionale `catch`-Bindung

· Eine Minute Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Die catch-Klausel von try-Anweisungen erforderte früher eine Bindung:

try {
doSomethingThatMightThrow();
} catch (exception) {
// ^^^^^^^^^
// Wir müssen die Bindung benennen, auch wenn wir sie nicht verwenden!
handleException();
}

In ES2019 kann catch jetzt ohne eine Bindung verwendet werden. Dies ist nützlich, wenn Sie das exception-Objekt im Code, der die Ausnahme behandelt, nicht benötigen.

try {
doSomethingThatMightThrow();
} catch { // → Keine Bindung!
handleException();
}

Unterstützung für optionale catch-Bindung

`String.prototype.trimStart` und `String.prototype.trimEnd`

· Eine Minute Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

ES2019 führt String.prototype.trimStart() und String.prototype.trimEnd() ein:

const string = '  hallo welt  ';
string.trimStart();
// → 'hallo welt '
string.trimEnd();
// → ' hallo welt'
string.trim(); // ES5
// → 'hallo welt'

Diese Funktionalität war zuvor über die nicht standardisierten Methoden trimLeft() und trimRight() verfügbar, welche aus Gründen der Abwärtskompatibilität weiterhin als Aliase für die neuen Methoden bestehen bleiben.

const string = '  hallo welt  ';
string.trimStart();
// → 'hallo welt '
string.trimLeft();
// → 'hallo welt '
string.trimEnd();
// → ' hallo welt'
string.trimRight();
// → ' hallo welt'
string.trim(); // ES5
// → 'hallo welt'