Heute, im achten Teil der Übersetzung des JavaScript-Handbuchs, werden wir die Funktionen der Sprache überprüfen, die nach der Veröffentlichung des ES6-Standards darin enthalten war. Auf die eine oder andere Weise sind wir schon früher auf viele dieser Möglichkeiten gestoßen, irgendwo, wo wir uns näher damit befassen, irgendwo, wo es für selbstverständlich gehalten wird. Dieser Abschnitt des Handbuchs soll zusammen mit der Offenlegung einiger Themen, die wir bisher nicht angesprochen haben, das Wissen eines unerfahrenen Entwicklers auf dem Gebiet des modernen JavaScript optimieren.
→
Teil 1: Erstes Programm, Sprachfunktionen, Standards→
Teil 2: Codestil und Programmstruktur→
Teil 3: Variablen, Datentypen, Ausdrücke, Objekte→
Teil 4: Funktionen→
Teil 5: Arrays und Loops→
Teil 6: Ausnahmen, Semikolons, Platzhalterliterale→
Teil 7: Strict Mode, dieses Schlüsselwort, Ereignisse, Module, mathematische Berechnungen→
Teil 8: Übersicht über die ES6-Funktionen→
Teil 9: Übersicht über die ES7-, ES8- und ES9-Standards
Über ES6
Der ES6-Standard, der korrekter wäre, ES2015 oder ECMAScript 2015 zu nennen (dies sind seine offiziellen Namen, obwohl jeder ihn ES6 nennt), erschien 4 Jahre nach der Veröffentlichung des vorherigen Standards - ES5.1. Es dauerte ungefähr zehn Jahre, um alles zu entwickeln, was in den ES5.1-Standard ging. Heutzutage ist alles, was in diesem Standard enthalten ist, zu den üblichen Werkzeugen des JS-Entwicklers geworden. Es ist zu beachten, dass ES6 wesentliche Änderungen an der Sprache vorgenommen hat (unter Beibehaltung der Abwärtskompatibilität mit den vorherigen Versionen). Um das Ausmaß dieser Änderungen einzuschätzen, kann angemerkt werden, dass die Größe des Dokuments, das den ES5-Standard beschreibt, ungefähr 250 Seiten beträgt, und dass der Standard ES6 in einem Dokument beschrieben wird, das bereits ungefähr 600 Seiten umfasst.
Die Liste der wichtigsten Neuerungen des ES2015-Standards kann Folgendes umfassen:
- Pfeilfunktionen
- Versprechen
- Generatoren
- Schlüsselwörter
let
und const
- Klassen
- Module
- Template Literal Support
- Unterstützung für Standardfunktionsparameter
- Spread-Operator
- Zerstörerische Aufgabe
- Objektliterale verbessern
for...of
Schleife- Unterstützung für
Map
and Set
Datenstrukturen
Betrachten Sie diese Möglichkeiten.
Pfeilfunktionen
Pfeilfunktionen haben das Erscheinungsbild von JavaScript-Code geändert. In Bezug auf das Erscheinungsbild macht ihre Verwendung Funktionsdeklarationen kürzer und einfacher. Hier ist eine reguläre Funktionsdeklaration.
const foo = function foo() {
Aber fast die gleiche (obwohl nicht ganz ähnlich wie oben) Pfeilfunktion.
const foo = () => {
Wenn der Hauptteil der Pfeilfunktion nur aus einer Zeile besteht, deren Ergebnis von dieser Funktion zurückgegeben werden muss, wird sie noch kürzer geschrieben.
const foo = () => doSomething()
Wenn die Pfeilfunktion nur einen Parameter akzeptiert, können Sie ihn wie folgt schreiben.
const foo = param => doSomething(param)
Es sollte beachtet werden, dass mit dem Aufkommen von Pfeilfunktionen gewöhnliche Funktionen nicht verschwunden sind, sie weiterhin im Code verwendet werden können und auf die gleiche Weise wie zuvor funktionieren.
Dieses Schlüsselwort ist in Pfeilfunktionen enthalten
Pfeilfunktionen haben
this
eigenen Wert nicht, sie erben ihn vom Ausführungskontext.
Dies behebt das Problem, für das bei Verwendung regulärer Funktionen Konstrukte wie
var that = this
, um den Kontext zu erhalten. Wie in den vorherigen Teilen des Handbuchs gezeigt wurde, wirkt sich diese Änderung jedoch ernsthaft auf die Funktionen der Arbeit mit Pfeilfunktionen und den Umfang ihrer Anwendung aus.
Versprechen
Mit Versprechungen können Sie das bekannte Problem der „Rückrufhölle“ loswerden, obwohl ihre Verwendung die Verwendung ziemlich komplexer Strukturen impliziert. Dieses Problem wurde im ES2017-Standard mit dem Aufkommen des
async/await
Konstrukts gelöst, das auf Versprechungen basiert.
JavaScript-Entwickler verwendeten Versprechen vor dem ES2015-Standard und verwendeten dafür verschiedene Bibliotheken (z. B. jQuery, q, deferred.js, vow). Dies zeigt die Bedeutung und Relevanz dieses Mechanismus. Verschiedene Bibliotheken implementieren es auf unterschiedliche Weise. Die Entstehung eines Standards in diesem Bereich kann als sehr positive Tatsache angesehen werden.
Hier ist Code, der mit Rückruffunktionen (Rückrufen) geschrieben wurde.
setTimeout(function() { console.log('I promised to run after 1s') setTimeout(function() { console.log('I promised to run after 2s') }, 1000) }, 1000)
Mit Versprechungen kann dies wie folgt umgeschrieben werden.
const wait = () => new Promise((resolve, reject) => { setTimeout(resolve, 1000) }) wait().then(() => { console.log('I promised to run after 1s') return wait() }) .then(() => console.log('I promised to run after 2s'))
Generatoren
Generatoren sind spezielle Funktionen, die ihre eigene Ausführung anhalten und fortsetzen können. Dadurch kann ein anderer Code ausgeführt werden, während der Generator inaktiv ist.
Der Generator entscheidet von selbst, dass er pausieren und zulassen muss, dass ein anderer Code, der darauf wartet, dass er an die Reihe kommt, ausgeführt wird. Gleichzeitig hat der Generator die Möglichkeit, seine Ausführung fortzusetzen, nachdem der Vorgang, auf dessen Ergebnisse er wartet, abgeschlossen ist.
All dies geschieht dank einer einzigen einfachen Keyword-
yield
. Wenn dieses Schlüsselwort im Generator gefunden wird, wird seine Ausführung angehalten.
Ein Generator kann viele Zeilen mit diesem Schlüsselwort enthalten und seine eigene Ausführung mehrmals anhalten. Generatoren werden mit dem Konstrukt
*function
deklariert. Dieses Sternchen vor der Wortfunktion sollte nicht für einen Zeiger-Dereferenzierungsoperator verwendet werden, der in Sprachen wie C, C ++ oder Go verwendet wird.
Generatoren markieren das Aufkommen eines neuen JavaScript-Programmierparadigmas. Insbesondere ermöglichen sie den bidirektionalen Datenaustausch zwischen dem Generator und anderem Code und ermöglichen die Erstellung langlebiger
while
Schleifen, die das Programm nicht „hängen“ lassen.
Betrachten Sie ein Beispiel, das die Funktionsweise von Generatoren veranschaulicht. Hier ist der Generator selbst.
function *calculator(input) { var doubleThat = 2 * (yield (input / 2)) var another = yield (doubleThat) return (input * doubleThat * another) }
Mit diesem Befehl initialisieren wir es.
const calc = calculator(10)
Dann wenden wir uns seinem Iterator zu.
calc.next()
Dieser Befehl startet einen Iterator und gibt ein solches Objekt zurück.
{ done: false value: 5 }
Hier passiert folgendes. Der Code führt eine Funktion unter Verwendung des
input
, der an den Generatorkonstruktor übergeben wird. Der Generatorcode wird ausgeführt, bis das Schlüsselwort
yield
darin gefunden wird. Zu diesem Zeitpunkt wird das Ergebnis der Division der
input
durch
2
, was, da die
input
10
, die Zahl
5
ergibt. Wir erhalten diese Nummer dank des Iterators und zusammen mit diesem Hinweis, dass der Generator noch nicht abgeschlossen ist (die Eigenschaft
done
in dem vom Iterator zurückgegebenen Objekt ist auf
false
), dh die Funktion wurde nur angehalten.
Beim nächsten Aufruf des Iterators übergeben wir die Nummer
7
an den Generator.
calc.next(7)
Als Antwort darauf gibt der Iterator das nächste Objekt an uns zurück.
{ done: false value: 14 }
Hier wurde die Zahl
7
verwendet, um den
doubleThat
Wert zu berechnen.
Auf den ersten Blick scheint der
input / 2
Code so etwas wie ein Argument für eine Funktion zu sein, aber dies ist nur der Wert, der bei der ersten Iteration zurückgegeben wird. Hier überspringen wir diesen Wert und verwenden den neuen Eingabewert
7
, indem wir ihn mit
2
multiplizieren. Danach gelangen wir zum zweiten
yield
Schlüsselwort. Infolgedessen beträgt der in der zweiten Iteration erhaltene Wert
14
.
Bei der nächsten Iteration, der letzten, übergeben wir die Nummer
100
an den Generator.
calc.next(100)
Als Antwort erhalten wir das folgende Objekt.
{ done: true value: 14000 }
Die Iteration ist abgeschlossen (das Schlüsselwort
yield
wird im Generator nicht mehr gefunden), das Ergebnis der Auswertung des Ausdrucks
(input * doubleThat * another)
im Objekt zurückgegeben,
(input * doubleThat * another)
-
10 * 14 * 100
und ein Hinweis auf die Fertigstellung des Iterators (
done: true
).
Schlüsselwörter let und const
JavaScript hat immer das Schlüsselwort
var
, um Variablen zu deklarieren. Solche Variablen haben einen Funktionsumfang. Mit
let
Schlüsselwörtern
let
und
const
können Sie Variablen und Konstanten deklarieren, die einen Blockbereich haben.
Dies bedeutet, dass beispielsweise eine Variable, die mit dem Schlüsselwort
let
in einer Schleife, in einem
if
Block oder in einem durch geschweifte Klammern begrenzten regulären Codeblock deklariert wurde, diesen Block nicht überschreitet. Mit
var
deklarierte Variablen werden nicht in solchen Blöcken gespeichert und werden in der Funktion verfügbar, auf deren Ebene sie deklariert werden.
Das
const
Schlüsselwort funktioniert genauso wie
let
, aber damit werden unveränderliche Konstanten deklariert.
Im modernen JS-Code wird das Schlüsselwort
var
selten verwendet. Es gab Platz für die Schlüsselwörter
let
und
const
. Gleichzeitig wird das Schlüsselwort
const
, was ungewöhnlich erscheinen mag, heute sehr häufig verwendet, was auf die Popularität der Ideen der Immunität von Entitäten in der modernen Programmierung hinweist.
Klassen
Es stellte sich heraus, dass JavaScript die einzige extrem verbreitete Sprache war, die das Prototyp-Vererbungsmodell verwendete. Programmierer, die von Sprachen, die den klassenbasierten Vererbungsmechanismus implementieren, zu JS wechseln, fühlten sich in einer solchen Umgebung unwohl. Mit dem ES2015-Standard wurde die Klassenunterstützung in JavaScript eingeführt. Dies ist im Wesentlichen „syntaktischer Zucker“ um JS-interne Mechanismen unter Verwendung von Prototypen. Dies wirkt sich jedoch darauf aus, wie genau JS-Anwendungen schreiben.
JavaScript-Vererbungsmechanismen sehen jetzt wie ähnliche Mechanismen in anderen objektorientierten Sprachen aus.
class Person { constructor(name) { this.name = name } hello() { return 'Hello, I am ' + this.name + '.' } } class Actor extends Person { hello() { return super.hello() + ' I am an actor.' } } var tomCruise = new Actor('Tom Cruise') console.log(tomCruise.hello())
Dieses Programm zeigt den Text
Hello, I am Tom Cruise. I am an actor
an der Konsole an
Hello, I am Tom Cruise. I am an actor
Hello, I am Tom Cruise. I am an actor
.
In JS-Klassen können Instanzvariablen nicht deklariert werden, sie müssen in den Konstruktoren initialisiert werden.
Klassenkonstruktor
Klassen haben eine spezielle Methode, den
constructor
, der aufgerufen wird, wenn eine Instanz der Klasse mit dem
new
Schlüsselwort erstellt wird.
▍ Stichwort super
Mit dem Schlüsselwort
super
können Sie von untergeordneten Klassen auf die übergeordnete Klasse zugreifen.
▍ Getter und Setter
Der Getter für eine Eigenschaft kann wie folgt festgelegt werden.
class Person { get fullName() { return `${this.firstName} ${this.lastName}` } }
Der Setter kann wie unten gezeigt beschrieben werden.
class Person { set age(years) { this.theAge = years } }
Sie arbeiten mit Gettern und Setzern, als wären sie keine Funktionen, sondern gewöhnliche Eigenschaften von Objekten.
Module
Vor dem ES2015-Standard gab es mehrere konkurrierende Ansätze für die Arbeit mit Modulen. Insbesondere sprechen wir über RequireJS- und CommonJS-Technologien. Diese Situation führte zu Meinungsverschiedenheiten in der Community der JS-Entwickler.
Dank der Standardisierung der Module in ES2015 normalisiert sich die Situation heutzutage allmählich.
▍ Module importieren
Module werden mit einem Konstrukt des Formularimports
import...from...
Hier sind einige Beispiele.
import * as something from 'mymodule' import React from 'react' import { React, Component } from 'react' import React as MyLibrary from 'react'
▍ Export von Modulen
Die internen Mechanismen des Moduls sind von außen geschlossen, aber aus dem Modul können Sie alles exportieren, was es anderen Modulen bieten kann. Dies erfolgt mit dem Schlüsselwort
export
.
export var foo = 2 export function bar() { }
▍ Vorlagenliterale
Vorlagenliterale sind eine neue Methode zur Beschreibung von Zeichenfolgen in JavaScript. So sieht es aus.
const aString = `A string`
Durch die Verwendung der Syntax von Vorlagenliteralen können Sie außerdem Ausdrücke in Zeichenfolgen einbetten und diese interpolieren. Dies erfolgt mit einer Konstruktion der Form
${a_variable}
. Hier ist ein einfaches Beispiel für seine Verwendung:
const v = 'test' const str = `something ${v}`
Hier ist ein komplizierteres Beispiel, das die Fähigkeit veranschaulicht, Ausdrücke auszuwerten und ihre Ergebnisse durch eine Zeichenfolge zu ersetzen.
const str = `something ${1 + 2 + 3}` const str2 = `something ${foo() ? 'x' : 'y' }`
Dank der Verwendung von Vorlagenliteralen ist es viel einfacher geworden, mehrzeilige Zeichenfolgen zu deklarieren.
const str3 = `Hey this string is awesome!`
Vergleichen Sie dies mit dem, was Sie tun mussten, um mehrzeilige Zeichenfolgen zu beschreiben, wenn Sie die Funktionen verwenden, die in der Sprache vor ES2015 verfügbar waren.
var str = 'One\n' + 'Two\n' + 'Three'
Standardfunktionsparameter
Jetzt unterstützen Funktionen die standardmäßig verwendeten Parameter - für den Fall, dass die entsprechenden Argumente beim Aufrufen von Funktionen nicht an sie übergeben werden.
const foo = function(index = 0, testing = true) { } foo()
Spread-Operator
Mit dem Spread-Operator (Erweiterungsoperator) können Sie Arrays, Objekte oder Zeichenfolgen erweitern. Dieser Operator sieht aus wie drei Punkte (
...
). Betrachten Sie es zunächst mit einem Array-Beispiel.
const a = [1, 2, 3]
So erstellen Sie ein neues Array basierend auf diesem Array.
const b = [...a, 4, 5, 6]
So erstellen Sie eine Kopie des Arrays.
const c = [...a]
Dieser Operator arbeitet auch mit Objekten. Hier erfahren Sie beispielsweise, wie Sie damit ein Objekt klonen.
const newObj = { ...oldObj }
Wenn Sie den Spread-Operator auf eine Zeichenfolge anwenden, können Sie ihn in ein Array konvertieren, dessen jedes Element ein Zeichen aus dieser Zeichenfolge enthält.
const hey = 'hey' const arrayized = [...hey]
Dieser Operator ist zusätzlich zu den oben genannten Varianten seiner Anwendung praktisch, wenn Funktionen aufgerufen werden, die eine normale Liste von Argumenten erwarten, und ihnen ein Array mit diesen Argumenten übergeben.
const f = (foo, bar) => {} const a = [1, 2] f(...a)
Früher wurde dies mit einer Konstruktion der Form
f.apply(null, a)
, aber ein solcher Code ist schwieriger zu schreiben und weniger lesbar.
Zerstörerische Aufgabe
Die Destrukturierungszuweisungstechnik ermöglicht es beispielsweise, ein Objekt zu nehmen, einige Werte daraus zu extrahieren und sie in benannte Variablen oder Konstanten zu setzen.
const person = { firstName: 'Tom', lastName: 'Cruise', actor: true, age: 54, } const {firstName: name, age} = person
Hier werden die Eigenschaften
firstName
und
age
aus dem Objekt abgerufen. Die
age
Eigenschaft wird in die mit demselben Namen deklarierte Konstante geschrieben, und die
firstName
Eigenschaft fällt nach der Extraktion in den Konstantennamen.
Die destruktive Zuordnung eignet sich auch für die Arbeit mit Arrays.
const a = [1,2,3,4,5] const [first, second, , , fifth] = a
Die
first
,
second
und
fifth
Konstante erhalten das erste, zweite und fünfte Element des Arrays.
Objektliterale verbessern
ES2015 hat die Möglichkeit zur Beschreibung von Objekten mithilfe von Objektliteralen erheblich erweitert.
▍ Vereinfachung der Einbeziehung von Variablen in Objekte
Bisher war es erforderlich, die folgende Konstruktion zu verwenden, um einer Eigenschaft eines Objekts eine Variable zuzuweisen.
const something = 'y' const x = { something: something }
Jetzt kann das Gleiche so gemacht werden.
const something = 'y' const x = { something }
▍ Prototypen
Der Prototyp des Objekts kann nun mithilfe der folgenden Konstruktion festgelegt werden.
const anObject = { y: 'y' } const x = { __proto__: anObject }
▍ Stichwort super
Mit dem Schlüsselwort
super
können Objekte auf Prototypobjekte zugreifen. Zum Beispiel, um ihre Methoden aufzurufen, die dieselben Namen wie die Methoden dieser Objekte selbst haben.
const anObject = { y: 'y', test: () => 'zoo' } const x = { __proto__: anObject, test() { return super.test() + 'x' } } x.test()
▍ Berechnete Eigenschaftsnamen
Berechnete Eigenschaftsnamen werden in der Phase der Objekterstellung gebildet.
const x = { ['a' + '_' + 'b']: 'z' } x.a_b
Für ... der Schleife
Im Jahr 2009 wurden im ES5-Standard
forEach()
-Schleifen angezeigt. Dies ist ein nützliches Design, dessen Nachteil die Tatsache ist, dass solche Zyklen sehr unpraktisch zu unterbrechen sind. Der Klassiker
for
Schleife in Situationen, in denen Sie die Ausführung der Schleife vor ihrem normalen Abschluss unterbrechen müssen, ist eine viel geeignetere Wahl.
In ES2015 ist ein
for...of
Zyklus erschienen, der sich einerseits durch seine prägnante Syntax und Bequemlichkeit für jeden auszeichnet und andererseits die Möglichkeit eines vorzeitigen Austritts aus dem Zyklus unterstützt.
Hier sind einige Beispiele
for...of
Schleifen.
Datenstrukturen zuordnen und festlegen
ES2015 führte Map- und
Set
Datenstrukturen ein (sowie deren „schwache“ Versionen
WeakMap
und
WeakSet
, deren Verwendung die Leistung des „Garbage Collector“ verbessert - des Mechanismus, der für die Speicherverwaltung in JS-Engines verantwortlich ist). Dies sind sehr beliebte Datenstrukturen, die vor dem Erscheinen ihrer offiziellen Implementierung mit den verfügbaren Sprachwerkzeugen nachgeahmt werden mussten.
Zusammenfassung
Heute haben wir die Funktionen des ES2015-Standards überprüft, die den aktuellen Status der Sprache stark beeinflusst haben. Unser nächstes Thema werden Funktionen der Standards ES2016, ES2017 und ES2018 sein.
Liebe Leser! Welche Neuerungen des ES6-Standards finden Sie am nützlichsten?
