born83.com frontend development

Ausblick: welche neuen Features erwarten uns in ECMAScript 2019?

Ecma International und der Standard-262

JavaScript wird von der Normungsorganisation ECMA international, die aus der European Computer Manufacturers Association hervorging, stetig weiterentwickelt.

Dazu werden von Ecma International Standards spezifiziert, die abwärtskompatibel sind und als Vorgabe für die Anbieter der Browser (Mozilla, Google, Microsoft, Apple, usw.) gelten. Für JavaScript erfolgt dies im Standard-262.

Der aktuelle Stand der Standardisierung für JavaScript ist ECMAScript 2018, welcher im Juni 2018 erschienen wurde. Neue Standards werden jährlich im Juni veröffentlicht, so dass davon ausgegangen werden darf, dass im Juni 2019 wohl ECMAScript 2019 als Standard veröffentlicht wird.

Das TC39 Komitee

Für die Weiterentwicklung des ECMAScript Standards ist ein Komitee der ECMA international zuständig: TC39, welches alle zwei Monate ein Meeting abhält. In der Regel finden diese Meetings in den USA statt. Einmal im Jahr soll aber auch ein Meeting in Europa angesetzt werden. So ist für 2019 ein Meeting des TC39 vom 4. bis 6. Juni bei der JSConf EU in Berlin geplant.

Der ECMAScript Entwicklungsprozess

Die Entwicklung neuer Features folgt einem festgelegten Prozess und sorgt dafür, dass für alle neuen Features der JavaScript Standards unter anderem eine zweifache Implementierung existiert und diese durch Akzeptanztests abgenommen werden.

Die Entwicklung von ECMAScript Erweiterungen in fünf Phasen

Der TC39 Prozess ist eingeteilt in fünf Phasen:

  1. Strohmann (Strawman)
    In dieser Phase können Vorschläge für Standards eingereicht werden. Dabei können alle Arten von Ideen vorgeschlagen werden, vorausgesetzt sie wurden nicht bereits schon zu einem früheren Zeitpunkt eingereicht. Einzige Voraussetzung ist, dass sie entweder von einem TC39 Mitglied kommen, oder aber einem Nicht-Mitglied, welches sich vorher bei Ecma International als RFTG Contributor registriert hat.

  2. Vorschlag (Proposal)
    In der zweiten Phase werden die Ideen dann konkretisiert: hier erfolgt eine Begründung für die Notwendigkeit der Aufnahme in den ECMAScript Standard, eine mögliche Lösung muss skizziert werden, sowie mögliche Herausforderungen identifiziert. Am Ende sollte eine Demo oder Polyfill zum Vorschlag vorliegen.

  3. Entwurf (Draft)
    Syntax und Semantik werden nun mit einer Notation zur formalen Spezifikation beschrieben. Dabei sollten alle elementaren Semantiken, Syntax und API abgedeckt sein, es können aber noch Platzhalter verwendet werden, sowie To-Dos existieren. Der Vorschlag wird entwickelt und eventuell in den ECMAScript Standard aufgenommen.

  4. Kandidat (Candidate)
    Für den Vorschlag muss nun eine komplette Spezifikationsbeschreibung vorliegen und Semantik, Syntax und API sind umfassend und vollständig zu beschreiben. Außerdem wurde die Spezifikationsbeschreibung sowohl von speziellen Prüfern sowie ECMAScript-Editoren überprüft und freigegeben.

  5. Fertigstellung (Finished)
    Ist der Kanidat in dieser Phase angelangt ist er fertig und wird für das nächste Release des ECMAScript Standards berücksichtigt.

Jeder kann sich einbringen und seine Ideen beisteuern

Wichtig ist noch einmal darauf hinzuweisen, dass prinzipiell jeder an der Weiterentwicklung von JavaScript mitwirken kann. Es bedarf lediglich der Registrierung bei Ecma International als RFTG Contributor und schon steht der Mitarbeit nichts mehr im Wege!

Mögliche neue Ergänzungen für den ECMAScript 2019 Standard

Einen Überblick über alle Vorschläge, die es bereits über die Phase Strohmann hinaus geschafft haben, bietet ein GitHub Repository von TC39. Stand heute (Januar 2019) existieren allerdings noch keine Spezifikationen, die sich in der letzten Phase Fertigstellung befinden. Das heißt, es liegen noch keine Ergänzungen für den ECMAScript Standard vor, die im Juni 2019 in JavaScript Einzug erhalten.

Es gibt aber diverse Vorschläge, die bereits die Phasen Strohmann, Vorschlag und Entwurf vollständig durchlaufen haben und sich bereits in der vorletzten Phase Kandidat befinden. Diese Kandidaten haben gute Chancen, im Juni als neue Features im Standard ECMAScript 2019 ausgerollt zu werden. Daher lohnt sich ein genauerer Blick auf diese Vorschläge:

globalThis

Der Vorschlag geht auf einen Tweet von Daniel Ehrenberg zurück, der darauf hinweist, dass in JavaScript keine Möglichkeit existiert, auf das globale Objekt zuzugreifen. So bietet jede Umgebungen unterschiedliche Möglichkeiten: im Browser erfolgt der Zugriff über die Schlüsselwörter window, self oder this, wohingegen unter node.js der Zugriff via global oder this erfolgt und in einer Shell wie d8 oder jsc nur this zur Verfügung steht.

Die Einführung von globalThis über alle Umgebungen hinweg würde dies vereinheitlichen.

Der Vorschlag wurde zuletzt im November 2018 präsentiert und es liegen Tests bereits vor - der Voschlag hat somit sehr gute Chancen, es in das nächste Release ECMAScript 2019 zu schaffen.

BigInt

BigInt soll als neuer primitiver Datentyp eingeführt werden und den primitiven Datentyp Number erweitern. Das Maximum von Number beträgt 2^53 - mit BigInt würde diese Grenze erweitert auf 64-Bit Integer, also 2^63.

Ein weiterer Vorteil dieser Erweiterung wäre eine Erweiterung des Zeitstempels (timestamp) in den Bereich von Nanosekunden.

Dieser Vorschlag wurde im Mai 2018 zuletzt präsentiert und ist somit noch aktuell. Tests liegen ebenfalls vor, somit hat dieser Vorschlag ebenfalls gute Chancen in ECMAScript 2019 als Standard berücksichtigt zu werden.

Array.prototype.{flat,flatMap}

Array.prototype.flat()

Die Methode Array.prototype.flat() erstellt aus einem verschachtelten Array mit mehreren Ebenen ein neues Array, welches alle Elemente auf einer Ebene enthält:

let array1 = [1, 2, [3, 4]];
console.log( array1.flat() );
// [1, 2, 3, 4]

Array.prototype.flatMap()

Die Methode Array.prototype.flatMap() ist eine verkettete Methode der Methoden map() und flat(). Zuerst wird die Methode map() angewandt, danach auf das Ergebnis die Methode flat():

let array1 = [2, 3, 4];
console.log( array1.flatMap((x) => [x, x * 2]) );       
// [2, 4, 3, 6, 4, 8]

Das Ergebnis ist identisch zu einem Aufruf der Methoden map() und flat() hintereinander:

let array1 = [2, 3, 4];
let mapped = array1.map( (x) => [x, x * 2]) );
// [[2, 4], [3, 6], [4, 8]]

let flatted = mapped.flat();
// [2, 4, 3, 6, 4, 8]

Auch für diesen Vorschlag liegen Tests vor. Die letzte Präsentation dieses Vorschlags ist zudem aus September 2018 und hat somit auch sehr gute Chancen, im nächsten Release ECMAScript 2019 als Standard Einzug zu erhalten.

String.prototype.trimStart / String.prototype.trimEnd

Die Methoden trimStart() und trimEnd() sind für den Datentyp String vorgesehen und würden einen String um Leerzeichen zu Beginn (trimStart) bzw. am Ende (trimEnd) bereinigen:

let nachricht = '   Hallo Welt!   ';

console.log( nachricht.trimStart() );
// "Hallo Welt!   "

console.log( nachricht.trimEnd() );
// "   Hallo Welt!" 

Als Alias für die Methoden sind zusätzlich trimLeft() und trimRight() vorgesehen.

Im Januar 2018 wurde der Vorschlag das letzte mal präsentiert. Er ist damit auch noch halbwegs aktuell. Da die Methoden nicht sehr komplex sind und auch schon Tests existieren, haben sie aber wohl auch gute Chancen in ECMAScript 2019 als Standard berücksichtigt zu werden.

Object.fromEntries

Mit der Methode Object.fromEntries() wird eine Liste key-value Paare in ein Objekt transferiert:

let obj = Object.fromEntries([
    ['foo', 0], 
    ['bar', 1]
]); 
console.log(obj)
// { foo: 0, bar: 1 }

Dieser Vorschlag wurde im Juli 2018 zuletzt präsentiert und ist somit auch noch aktuell. Auch hier liegen Tests vor und die Chance, dass er als Standard für das Release 2019 von ECMAScript berücksichtigt wird, ist dementsprechend hoch.

dynamic import()

Dieser Vorschlag ist ein Ansatz, die bereits existierende Methode import() zu erweitern. Bisher funktioniert die Methode import() statisch. Auf diese Weise lassen sich mit Hilfe der Methode Module vor der Ausführung an den Scope binden. Es ist jedoch nicht möglich, Module dynamisch zur Laufzeit zu laden.

Durch diesen Vorschlag würde die Methode import() erweitert, so dass sie wie eine Funktion aufgerufen werden könnte. Damit wäre es möglich, Module dynamisch während der Laufzeit zu laden und abhängig davon individuellen Programm-Code auszuführen. In diesem Fall wäre die Methode import() wie ein Promise verwendbar:

import('/das-modul.js')
.then((module) => {
    // Modul erfolgreich geladen ...
})
.catch(err => {
    // Fehlerbehandlung ...
});

Zwar sind Tests für diesen Vorschlag umgesetzt, allerdings ist dieser Vorschlag bereits älter - die letzte Präsentation dieses Vorschlags ist aus November 2016. Ob dieser Vorschlag im nächsten Release ECMAScript 2019 als Standard ausgerollt wird, bleibt abzuwarten.

Class field declarations for JavaScript

Bisher werden die Eigenschaften der Instanzen einer Klasse in JavaScript in der entsprechenden Methode constructor() definiert:

class Produkt {
    constructor() {
        this.preis = 0;
    }
}

Nach dem Vorschlag wäre zukünftig möglich, die Eigenschaften direkt auf der Ebene der Klasse zu definieren, diese also aus der constructor() Methode heraus zu ziehen:

class Produkt {
    preis = 0;

    constructor() {

    }
}

Dadurch wird die Struktur des Codes wesentlich verbessert - der Code ist besser lesbar. Außerdem durchlaufen die Instanzen weniger Zustandsübergänge, die deklarierten Felder sofort vorhanden sind.

Dieser Vorschlag wurde im September 2018 zuletzt präsentiert, ist somit aktuell. Es existieren jedoch laut Übersicht Stand heute jedoch noch keine Tests. Deshalb bleibt es abzuwarten, ob dieser Vorschlag in der Version ECMAScript 2019 aufgenommen wird.

Zusätzlich ist dieser Vorschlag auch mit dem nächsten Vorschlag verbunden, der noch kontrovers diskutiert wird.

Private methods and getter/setters for JavaScript classes

Dieser Vorschlag zielt darauf ab, Variablen, Methoden und Zugriffsfunktionen in JavaScript als privat deklarierbar zu machen. Dies wäre eine ziemlich drastische Änderung, denn bisher ist es in JavaScript nicht möglich, Elemente als privat zu deklarieren.

Der aktuelle Stand des Vorschlags sieht es vor, dass zur Auszeichnung als privat der Name der Methode, Zugriffsfunktion oder Variablen mit einer vorangestellten Raute # gekennzeichnet wird:

class Diesel extends PKW {  
    constructor(name) {
        super(name);
        this._name = name;    // public deklarierte Variable
        this.#_verbrauch = 0; // privat deklarierte Variable        
    }

    get name() {
        return this._name;
    }

    // private Methode
    get #verbrauch() { 
        return this.#_verbrauch; 
    }

    // private Methode
    set #verbrauch(neuerVerbrauch) {
        this.#_verbrauch = neuerVerbrauch;
    }       

    get status() {
        return "'" + this.name + "' aktueller Verbrauch: " + this.#verbrauch + ' l/100km'
    }

    fahre() {
        this.#verbrauch = 10;
    }

    fahreSchnell() {
        this.#verbrauch = 15;
    }

    halte() {
        this.#verbrauch = 0;
    }
}

const auto = new Diesel("Nationenfahrzeug Überfahrt");

auto.fahre();
console.log( auto.status );
// 'Nationenfahrzeug Überfahrt' aktueller Verbrauch: 10 l/100km

auto.fahreSchnell();
console.log( auto.status );
// 'Nationenfahrzeug Überfahrt' aktueller Verbrauch: 15 l/100km

auto.halte();
console.log( auto.status );
// 'Nationenfahrzeug Überfahrt' aktueller Verbrauch: 0 l/100km

Der Zugriff auf die privaten Zugriffsmethoden get #verbrauch() und set #verbrauch() ist nun nur noch innerhalb der Klasse möglich. Eine direkte Manipulation von Außen über die Variable auto wäre demnach nicht erlaubt.

Wichtig ist noch, dass der Vorschlag keine private Deklaration vorsieht für Variablen und Methoden, die dynamisch während der Laufzeit erstellt und an Objekte gebunden werden. Auch in Objekt-Literalen sind private Methoden und Variablen nicht vorgesehen.

Dieser Vorschlag erreichte Phase 3 bereits im September 2017 und wurde seitdem vielfach diskutiert. So wurde beispielsweise auch über eine Notation angelehnt an andere Programmiersprachen mit dem Schlüsselwort private nachgedacht, die vielen Nutzern wohl besser gefallen würde als die Verwendung der Raute # zur privaten Kennzeichnung.

Auch dieser Vorschlag ist bereits etwas älter - die letzte Präsentation fand allerdings im September 2018 statt und ist somit noch aktuell. Allerdings handelt es sich bei diesem Vorschlag um eine Erweiterung mit weitreichenden Folgen. Bislang gibt es in JavaScript wie gesagt keine Möglichkeit Variablen oder Methoden einer Klasse als privat zu deklarieren.

Dass der Vorschlag schon im nächsten Standard ECMAScript 2019 berücksichtigt wird, dürfte eher gering sein. Das Thema ist einfach sehr kontrovers, darüber hinaus gibt es zwar einige Implementierungen gibt, diese befinden sich aber noch in der Entwicklung. Tests sind dementsprechend auch noch nicht implementiert.

Static class features

Dieser Vorschlag basiert unter anderem auf dem vorhergehenden Vorschlag und würde JavaScript Klassen um drei neue Features ergänzen:

  • Statische öffentliche Variablen (Static public fields)
  • Statische private Methoden (Static private methods)
  • Statische private Variablen (Static private fields)

Diese drei Features würden die Syntax von JavaScript Klassen um Klassenvariablen und Klassenmethoden erweitern.

Implementieren lässt sich das Verhalten auch jetzt schon:

class Warenkorb {
    constructor() {
        Warenkorb.zaehler++;
    }
}
Warenkorb.zaehler = 0;

const korb1 = new Warenkorb();
const korb2 = new Warenkorb();
const korb3 = new Warenkorb();
console.log(Warenkorb.zaehler);

Die Klassenvariable wird instanziiert und bei jedem Aufruf der Klasse um eins erhöht. Es funktioniert, ist aber nicht so übersichtlich und gut lesbar, wie die Erweiterung der Klasse um eine Klassenvariable mit dem Schlüsselwort static:

class Warenkorb {
    static zaehler = 0;
    constructor() {
        Warenkorb.zaehler++;
    }
}

Die letzte Präsentation dieses Vorschlags ist zwar aus Mai 2018 und hätte theoretisch somit auch sehr gute Chancen, im nächsten Release ECMAScript 2019 als Standard Einzug zu erhalten. Allerdings hängt der private Teil natürlich wesentlich vom Vorschlag Private methods and getter/setters for JavaScript classes ab.

Am wahrscheinlichsten ist es daher wohl, dass zunächst Klassenvariablen und Klassenmethoden mit Hilfe des Schlüsselworts static eingeführt werden und später die private Deklaration nachgezogen wird, sofern man sich dazu entscheidet diese als Standard in JavaScript einzuführen.

Für Klassenvariablen existieren Implementierungen in Babel und V8, außerdem wurden bereits Tests hierfür geschrieben. Es ist somit sehr gut möglich, dass ECMAScript 2019 bereits Klassenvariablen unterstützen wird.

Fazit: was bringt ECMAScript 2019?

Ein abschließendes Fazit zum kommenden ECMAScript 2019 Release lässt sich momentan noch nicht ziehen, da es Stand jetzt (Januar 2019) noch sehr schwer abzusehen ist, welche Erweiterungen es in das finale Release von ECMAScript 2019 schaffen werden.

Sehr wahrscheinlich sind die Ergänzung um den primitiven Datentyp BigInt, eine einheitliche Variable für das globale Objekt mit globalThis, die Methoden flat() und flatMap() für Arrays, trimStart() und trimEnd() für Strings, sowie Object.fromEntries().

Fraglich aber nicht unwahrscheinlich ist die Erweiterung der Methode import() zur dynamischen Verwendung, sowie eine Anpassung der Syntax für Klassen in JavaScript, um:

  • eine einfachere und übersichtlichere Möglichkeit Variablen in Klassen zu definieren,
  • Klassenvariablen und -methoden direkt über das Schlüsselwort static zu definieren.

Eher unwahrscheinlich dürfte wohl die Einführung von privaten Variablen und Methoden im Release ECMAScript 2019 sein. Durch die Diskussionen rund um das Thema sprechen eher für eine Einführung in das Release ECMAScript 2020.´

https://de.wikipedia.org/wiki/Ecma_International

https://www.ecma-international.org/publications/standards/Ecma-262.htm

https://www.ecma-international.org/ecma-262/9.0/index.html#Title

https://www.ecma-international.org/memento/tc39.htm

https://tc39.github.io/process-document/

https://github.com/tc39/proposals

https://tc39.github.io/agreements/contributor/

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap