JavaScript ES6: Schwächen

Im Juni 2018 feierte der Standard ECMAScript 2015 ( ES6 ) sein dreijähriges Bestehen. In ES6 sind zum einen viele neue JavaScript-Funktionen erschienen, und zum anderen beginnt mit diesem Standard eine neue Ära der Sprachentwicklung. Darüber hinaus war dies die letzte groß angelegte Version von JS, da TC39 jetzt das Schema für die Ausgabe kleiner jährlicher Ausgaben des Standards anwendet und es nicht alle paar Jahre erneut herausbringt.



In den letzten 4 Jahren hat ES6 zu Recht allgemeine Aufmerksamkeit erregt. Der Autor des Materials, dessen Übersetzung wir heute veröffentlichen, sagt, dass er dank Babel die ganze Zeit den gesamten Code mit der modernen Version der JS-Spezifikationen geschrieben hat. Er glaubt, dass genug Zeit vergangen ist, um die neuen Funktionen von ES6 kritisch zu analysieren. Insbesondere interessiert er sich für das, was er für einige Zeit verwendet hat, und hat es dann nicht mehr verwendet, weil es seinen Code verschlechtert hat.

Über JS-Schwächen


Douglas Crockford schrieb in seinem Buch JavaScript: Strengths auch darüber, was als Schwächen der Sprache angesehen werden kann. Dies ist etwas, das seiner Meinung nach nicht wert ist, verwendet zu werden. Glücklicherweise gibt es unter den Innovationen von ES6 nichts so unansehnliches wie einige der alten problematischen Funktionen von JS, wie den laxen Gleichheitsoperator, der die implizite Typkonvertierung durchführt, die eval() -Funktion und die with Anweisung. Die neuen Funktionen von ES6 sind viel besser gestaltet. Es gibt jedoch einige Dinge in ihm, die ich vermeide. Die Funktionen, die auf meiner Liste der JS-Schwachstellen stehen, sind aus folgenden Gründen in dieser Liste aufgeführt:

  • Sie sind im Wesentlichen „Fallen“. Das heißt, sie scheinen darauf ausgelegt zu sein, bestimmte Aktionen auszuführen, und in den meisten Fällen funktionieren sie wie erwartet. Manchmal verhalten sie sich jedoch unerwartet, was leicht zu Fehlern führen kann.
  • Sie erhöhen das Sprachvolumen im Austausch für kleine Vorteile. Solche Möglichkeiten bieten dem Entwickler einige kleine Vorteile, erfordern jedoch jemanden, der versucht, seinen Code herauszufinden, um Kenntnisse über bestimmte Mechanismen zu haben, die normalerweise irgendwo versteckt sind. Dies gilt in zweifacher Hinsicht für API-Funktionen. Wenn Sie diese Funktion verwenden, bedeutet dies, dass anderer Code, der mit Code interagiert, der von einem bestimmten Entwickler geschrieben wurde, die Anwendung dieser API-Funktion kennen muss.

Lassen Sie uns nun anhand dieser Überlegungen über die Schwächen von ES6 sprechen.

Schlüsselwort const


Vor ES6 konnten Variablen in JavaScript mit dem Schlüsselwort var deklariert werden. Außerdem konnten Variablen überhaupt nicht deklariert werden, dann fallen sie, selbst wenn sie in Funktionen verwendet werden, in den globalen Bereich. Eigenschaften von Objekten können die Rolle von Variablen spielen, und Funktionen werden mit dem function deklariert. Das Schlüsselwort var hat bestimmte Funktionen.

Auf diese Weise können Sie Variablen erstellen, die dem globalen Objekt hinzugefügt werden oder deren Umfang durch Funktionen begrenzt ist. Das Schlüsselwort var berücksichtigt jedoch keine Codeblöcke. Darüber hinaus können Sie auf eine Variable verweisen, die mit dem Schlüsselwort var im Code vor dem Befehl für ihre Deklaration deklariert wurde. Dieses Phänomen wird als Erhöhen von Variablen bezeichnet. Wenn diese Funktionen nicht berücksichtigt werden, können sie zu Fehlern führen. Um die Situation zu korrigieren, führte ES6 zwei neue Schlüsselwörter für die Deklaration von Variablen ein: let und const . Sie lösten die Hauptprobleme var . Wir sprechen nämlich über die Tatsache, dass Variablen, die mit diesen Schlüsselwörtern deklariert wurden, einen Blockbereich haben, sodass beispielsweise eine in einer Schleife deklarierte Variable außerhalb dieser Schleife nicht sichtbar ist. Darüber hinaus ermöglicht die Verwendung von let und const keinen Zugriff auf Variablen, bevor diese deklariert werden. Dies führt zu einem ReferenceError Fehler. Dies war ein großer Schritt nach vorne. Das Auftauchen von zwei neuen Schlüsselwörtern sowie deren Funktionen führte jedoch zu zusätzlicher Verwirrung.

Der Wert einer Variablen (Konstante), die mit dem Schlüsselwort const deklariert wurde, kann nach der Deklaration nicht überschrieben werden. Dies ist der einzige Unterschied zwischen const und let . Diese neue Gelegenheit sieht nützlich aus und kann wirklich einige Vorteile bringen. Das Problem ist das const Schlüsselwort selbst. Die Art und Weise, wie sich die deklarierten Konstanten verhalten, entspricht nicht dem, was die meisten Entwickler mit dem Konzept der „Konstante“ assoziieren.

 const CONSTANT = 123; //      "TypeError: invalid assignment to const `CONSTANT`" CONSTANT = 345; const CONSTANT_ARR = [] CONSTANT_ARR.push(1) //     [1]  -    console.log(CONSTANT_ARR) 

Die Verwendung des Schlüsselworts const verhindert, dass ein neuer Wert in eine Konstante geschrieben wird, macht jedoch Objekte, auf die von solchen Konstanten verwiesen wird, nicht unveränderlich. Diese Funktion bietet einen schlechten Schutz gegen Wertänderungen bei der Arbeit mit den meisten Datentypen. Aufgrund der Tatsache, dass die Verwendung von const zu Verwirrung führen kann, und aufgrund der Tatsache, dass das Vorhandensein von const redundant aussieht, wenn das Schlüsselwort let vorhanden ist, habe ich mich entschieden, immer let .

Tagged Template Strings


Das Schlüsselwort const ist ein Beispiel dafür, wie eine Spezifikation zu viele Möglichkeiten zur Lösung zu weniger Probleme schafft. Bei getaggten Vorlagenzeichenfolgen ist die Situation umgekehrt. Die Syntax solcher Zeichenfolgen wurde vom TC39-Komitee als eine Möglichkeit zur Lösung von Zeichenfolgeninterpolation und mehrzeiligen Zeichenfolgen angesehen. Dann beschlossen sie, diese Möglichkeit durch den Einsatz von Makros zu erweitern.

Wenn Sie noch nie markierte Musterzeichenfolgen gesehen haben, denken Sie daran, dass sie ein bisschen wie Zeichenfolgendekoratoren sind. Hier ist ein Beispiel für die Arbeit mit ihnen mit MDN :

 var person = 'Mike'; var age = 28; function myTag(strings, personExp, ageExp) { var str0 = strings[0]; // "that " var str1 = strings[1]; // " is a " //  (  ) //     , //  ,      . // var str2 = strings[2]; var ageStr; if (ageExp > 99){   ageStr = 'centenarian'; } else {   ageStr = 'youngster'; } return str0 + personExp + str1 + ageStr; } var output = myTag`that ${ person } is a ${ age }`; console.log(output); // that Mike is a youngster 

Mit Tags versehene Vorlagenzeichenfolgen können nicht als völlig nutzlos bezeichnet werden. Hier ist eine Übersicht über einige ihrer Anwendungen. Sie sind beispielsweise beim Löschen von HTML-Code hilfreich. Derzeit zeigt ihre Anwendung den genauesten Ansatz in Situationen, in denen Sie dieselbe Operation für alle Eingabedaten einer beliebigen Zeichenfolgenvorlage ausführen müssen. Dies ist jedoch relativ selten. Sie können dies auch mit der entsprechenden API tun (obwohl eine solche Lösung länger ist). Um die meisten Probleme zu lösen, ist die Verwendung der API nicht schlechter als die Verwendung von mit Tags versehenen Vorlagenzeichenfolgen. Diese Funktion fügt der Sprache keine neuen Funktionen hinzu. Sie fügt neue Ansätze für die Arbeit mit Daten hinzu, die denen vertraut sein sollten, die Code lesen müssen, der mit markierten Vorlagenzeichenfolgen geschrieben wurde. Und ich bemühe mich sicherzustellen, dass mein Code so sauber und verständlich wie möglich bleibt.

Überarbeitete destruktive Zuweisungsausdrücke


Einige Funktionen der Sprache sehen gut aus, wenn sie zur Lösung einfacher Aufgaben verwendet werden. Wenn Aufgaben jedoch komplexer werden, können diese Funktionen außer Kontrolle geraten. Zum Beispiel mag ich den ternären bedingten Operator:

 let conferenceCost = isStudent ? 50 : 200 

Mit dem mit seiner Hilfe geschriebenen Code wird es jedoch schwierig zu verstehen, ob Sie mit diesem Operator verschachtelte Konstruktionen verwenden:

 let conferenceCost = isStudent ? hasDiscountCode ? 25 : 50 : hasDiscountCode ? 100 : 200; 

Gleiches gilt für die destruktive Zuordnung. Mit diesem Mechanismus können Sie die Werte von Variablen aus Objekten oder Arrays abrufen:

 let {a} = {a: 2, b: 3}; let [b] = [4, 5]; console.log(a, b) // 2, 4 

Darüber hinaus können Sie bei Verwendung Variablen umbenennen, verschachtelte Werte abrufen und Standardwerte festlegen:

 let {a: val1} = {a: 2, b: 3}; let [{b}] = [{a:3, b:4} , {c: 5, d: 6}]; let {c=6} = {a: 2, c: 5}; let {d=6} = {a: 2, c: 5}; console.log(val1, b, c, d) // 2, 4, 5, 6 

All dies ist wunderbar - bis es darum geht, komplexe Ausdrücke mit all diesen Funktionen zu erstellen. Im folgenden Ausdruck werden beispielsweise 4 Variablen deklariert: userName , eventType , eventDate und eventId . Ihre Werte werden von verschiedenen Stellen in der Struktur des eventRecord Objekts übernommen.

 let eventRecord = { user: { name: "Ben M", email: "ben@m.com" }, event: "logged in", metadata: { date: "10-10-2017" }, id: "123" }; let { user: { name: userName = "Unknown" }, event: eventType = "Unknown Event", metadata: [date: eventDate], id: eventId } = obj; 

Einen solchen Code zu verstehen ist fast unmöglich. Dieses Problem kann mit viel besser lesbarem Code gelöst werden, wenn Sie mehrere Destrukturierungsvorgänge verwenden oder diese vollständig aufgeben.

 let eventRecord = { user: { name: "Ben M", email: "ben@m.com" }, event: "logged in", metadata: { date: "10-10-2017" }, id: "123" }; let userName = eventRecord.user.userName || 'Unknown'; let eventDate = eventRecord.metadata.date; let {event:eventType='UnknownEvent', id:eventId} = eventRecord; 

Ich habe keine klare Richtlinie, die darauf hinweist, dass der Ausdruck der destruktiven Aufgabe überarbeitet werden muss. Jedes Mal, wenn ich einen ähnlichen Ausdruck betrachte und nicht sofort verstehen kann, welches Problem er löst und welche Variablen darin verwendet werden, ist es an der Zeit, den Code zu vereinfachen, um seine Lesbarkeit zu verbessern.

Standardexport


ES6 hat eine nette Funktion. Es besteht darin, wie seine Entwickler die Standardisierung dessen, was zuvor getan wurde, mit Hilfe verschiedener Bibliotheken angegangen sind, die häufig miteinander konkurrieren. So erschienen in der Spezifikation Klassen, Versprechen, Module. Dies ist alles, was die JS-Entwicklergemeinde vor ES6 verwendet hat und in Bibliotheken von Drittanbietern gefunden hat. Zum Beispiel sind ES6-Module ein hervorragender Ersatz für das, was in den AMD / CommonJS-Formatkrieg übergegangen ist, und bieten eine bequeme Syntax für die Organisation von Importen.

ES6-Module unterstützen zwei Hauptmethoden zum Exportieren von Werten: benannter Export und Standardexport oder Standardexport:

 const mainValue = 'This is the default export export default mainValue export const secondaryValue = 'This is a secondary value; export const secondaryValue2 = 'This is another secondary value; 

Ein Modul kann mehrere benannte Exportbefehle verwenden, jedoch nur einen Standardexportbefehl. Wenn Sie importieren, was mit dem Standardexportbefehl exportiert wurde, können Sie in der Importdatei jedem Namen, der standardmäßig exportiert wird, einen beliebigen Namen geben, da während dieses Vorgangs keine Namen gesucht werden. Wenn Sie den benannten Export verwenden, müssen Sie die Variablennamen aus den exportierenden Dateien verwenden, obwohl auch das Umbenennen möglich ist.

 //   import renamedMainValue from './the-above-example'; //   import {secondaryValue} from './the-above-example'; //     import {secondaryValue as otherValue} from './the-above-example'; 

Der Standardexport fand bei den Entwicklern des ES6-Standards besondere Beachtung und erstellte absichtlich eine einfachere Syntax dafür. In der Praxis konnte ich jedoch feststellen, dass die Verwendung der benannten Exporttechnologie aus den folgenden Gründen vorzuziehen ist.

  1. Bei Verwendung des benannten Exports entsprechen die Namen der exportierten Variablen standardmäßig den Namen der importierten Variablen, was die Suche nach Personen vereinfacht, die keine intelligenten Entwicklungstools verwenden.
  2. Bei der Verwendung benannter Exporte erhalten Programmierer, die intelligente Entwicklungstools verwenden, so praktische Funktionen wie den automatischen Import .
  3. Mit benannten Exporten können Sie alles, was Sie wollen, in den richtigen Mengen einheitlich aus den Modulen exportieren. Der Standardexport beschränkt den Entwickler darauf, nur einen einzelnen Wert zu exportieren. Um dieses Problem zu umgehen, können Sie den Export eines Objekts mit mehreren Eigenschaften anwenden. Dieser Ansatz verliert jedoch den Wert des Tree-Shaking-Algorithmus, der zum Reduzieren der Größe von JS-Anwendungen verwendet wird, die von so etwas wie Webpack erstellt wurden. Die Verwendung ausschließlich benannter Module vereinfacht die Arbeit.

Im Allgemeinen kann festgestellt werden, dass das Benennen von Entitäten eine gute Vorgehensweise ist, da Sie sie sowohl im Code als auch in Gesprächen über diesen Code eindeutig identifizieren können. Deshalb verwende ich den benannten Export.

Zusammenfassung


Sie haben gerade die Funktionen von ES6 kennengelernt, die laut dem Autor dieses Materials nicht erfolgreich sind. Vielleicht schließen Sie sich dieser Meinung an, vielleicht auch nicht. Jede Programmiersprache ist ein komplexes System, dessen Funktionen aus verschiedenen Blickwinkeln betrachtet werden können. Wir hoffen jedoch, dass dieser Artikel allen nützlich sein wird, die klaren und qualitativ hochwertigen Code schreiben möchten.

Liebe Leser! Gibt es etwas in modernem JavaScript, das Sie vermeiden möchten?

Source: https://habr.com/ru/post/de417383/


All Articles