10. Destrukturierung

10. Destrukturierung #

  • 10.1. Übersicht
    • 10.1.1. Objektzerstörung
    • 10.1.2. Array-Destrukturierung
    • 10.1.3. Wo kann Destrukturierung eingesetzt werden?
  • 10.2. Hintergrund: Daten konstruieren versus Daten extrahieren
  • 10.3. Muster für die Destrukturierung
    • 10.3.1. Wählen Sie, was Sie brauchen
  • 10.4. Wie greifen Muster auf die Innereien von Werten zu?
    • 10.4.1. Objektmuster zwingen Werte zu Objekten
    • 10.4.2. Array-Muster arbeiten mit Iterablen
  • 10.5. Standardwerte
    • 10.5.1. undefined löst Standardwerte aus
    • 10.5.2. Standardwerte werden bei Bedarf berechnet
    • 10.5.3. Standardwerte können sich auf andere Variablen im Muster
    • 10.5.4 beziehen. Standardwerte für Muster
    • 10.5.5. Komplexere Standardwerte
  • 10.6. Weitere Funktionen zur Objektdestrukturierung
    • 10.6.1. Eigenschaftswert Abkürzungen
    • 10.6.2. Berechnete Eigenschaftsschlüssel
  • 10.7. Weitere Array-Destrukturierungsfunktionen
    • 10.7.1. Elision
    • 10.7.2. Rest-Operator (...)
  • 10.8. Sie können mehr als nur Variablen zuweisen
  • 10.9. Fallstricke der Destrukturierung
    • 10.9.1. Beginnen Sie eine Anweisung nicht mit einer geschweiften Klammer
  • 10.10. Beispiele für Destrukturierung
    • 10.10.1. Destrukturierung zurückgegebene Arrays
    • 10.10.2. Destrukturierung zurückgegebener Objekte
    • 10.10.3. Array-Destrukturierung iterierbarer Werte
    • 10.10.4. Mehrere Rückgabewerte
  • 10.11. Der Destrukturierungsalgorithmus
    • 10.11.1. Der Algorithmus
    • 10.11.2. Anwenden des Algorithmus

10.1 Übersicht #

Die Destrukturierung ist eine bequeme Möglichkeit, mehrere Werte aus Daten zu extrahieren, die in (möglicherweise verschachtelten) Objekten und Arrays gespeichert sind. Es kann an Orten verwendet werden, an denen Daten empfangen werden (z. B. auf der linken Seite einer Zuweisung). Wie die Werte extrahiert werden, wird über Muster angegeben (Beispiele finden Sie weiter).

10.1.1 Objekt-Destrukturierung #

Objekt-Destrukturierung:

const obj = { first: 'Jane', last: 'Doe' };const {first: f, last: l} = obj; // f = 'Jane'; l = 'Doe'// {prop} is short for {prop: prop}const {first, last} = obj; // first = 'Jane'; last = 'Doe'

Destrukturierung hilft bei der Verarbeitung von Rückgabewerten:

const obj = { foo: 123 };const {writable, configurable} = Object.getOwnPropertyDescriptor(obj, 'foo');console.log(writable, configurable); // true true

10.1.2 Array-Destrukturierung #

Array-Destrukturierung (funktioniert für alle iterierbaren Werte):

const iterable = ;const  = iterable; // x = 'a'; y = 'b'

Destrukturierung hilft bei der Verarbeitung von Rückgabewerten:

const  = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec('2999-12-31');

10.1.3 Wo kann Destrukturierung eingesetzt werden? #

Destrukturierung kann an den folgenden Stellen verwendet werden (ich zeige Array-Muster, um zu demonstrieren; Objektmuster funktionieren genauso gut):

// Variable declarations:const  = ;let  = ;var  = ;// Assignments: = ;// Parameter definitions:function f() { ··· }f();

Sie können auch in einer for-of -Schleife destrukturieren:

const arr = ;for (const  of arr.entries()) { console.log(index, element);}// Output:// 0 a// 1 b

10.2 Hintergrund: Konstruieren von Daten im Vergleich zum Extrahieren von Daten #

Um vollständig zu verstehen, was Destrukturierung ist, untersuchen wir zunächst den breiteren Kontext.

JavaScript verfügt über Operationen zum Erstellen von Daten, jeweils eine Eigenschaft:

const obj = {};obj.first = 'Jane';obj.last = 'Doe';

Die gleiche Syntax kann zum Extrahieren von Daten verwendet werden. Wieder eine Eigenschaft nach der anderen:

const f = obj.first;const l = obj.last;

Darüber hinaus gibt es eine Syntax zum gleichzeitigen Erstellen mehrerer Eigenschaften über ein Objektliteral:

const obj = { first: 'Jane', last: 'Doe' };

Vor ES6 gab es keinen entsprechenden Mechanismus zum Extrahieren von Daten. Das ist es, was Destrukturierung ist – Sie können mehrere Eigenschaften aus einem Objekt über ein Objektmuster extrahieren. Zum Beispiel auf der linken Seite einer Zuweisung:

const { first: f, last: l } = obj;

Sie können Arrays auch über Muster zerstören:

const  = ; // x = 'a'; y = 'b'

10.3 Muster für die Destrukturierung #

Die folgenden zwei Parteien sind an der Destrukturierung beteiligt:

  • Destrukturierungsquelle: Die Daten, die destrukturiert werden sollen. Zum Beispiel die rechte Seite einer Destrukturierungszuweisung.
  • Destrukturierungsziel: das Muster, das für die Destrukturierung verwendet wird. Zum Beispiel die linke Seite einer Destrukturierungszuweisung.

Das Destrukturierungsziel ist eines von drei Mustern:

  • Zuordnung Ziel. Zum Beispiel: x
    • Ein Zuweisungsziel ist normalerweise eine Variable. Bei der Destrukturierungszuweisung haben Sie jedoch mehr Optionen, wie ich später erläutern werde.
  • Objekt Muster. Zum Beispiel: { first: "pattern", last: "pattern" }
    • Die Teile eines Objektmusters sind Eigenschaften, die Eigenschaftswerte sind wiederum Muster (rekursiv).
  • Array-Muster. Zum Beispiel:
    • Die Teile eines Array-Musters sind Elemente, die Elemente sind wiederum Muster (rekursiv).

Das bedeutet, dass Sie Muster beliebig verschachteln können.:

const obj = { a: , b: true };const { a:  } = obj; // f = 123

10.3.1 Wählen Sie, was Sie brauchen #

Wenn Sie ein Objekt zerstören, erwähnen Sie nur die Eigenschaften, an denen Sie interessiert sind:

const { x: x } = { x: 7, y: 3 }; // x = 7

Wenn Sie ein Array zerstören, können Sie nur ein Präfix extrahieren:

const  = ; // x='a'; y='b';

10.4 Wie greifen Muster auf die Innereien von Werten zu? #

Wie greift der patternin einer Zuweisung pattern = someValue auf das zu, was sich in someValue befindet?

10.4.1 Objektmuster zwingen Werte zu Objekten #

Das Objektmuster zwingt Destrukturierungsquellen zu Objekten, bevor auf Eigenschaften zugegriffen wird. Das bedeutet, dass es mit primitiven Werten funktioniert:

const {length : len} = 'abc'; // len = 3const {toString: s} = 123; // s = Number.prototype.toString
10.4.1.1 Fehler bei der Objektdestruktur eines Werts #

Der Zwang zum Objekt wird nicht über Object() , sondern über die interne Operation ToObject() ausgeführt. Die beiden Operationen behandeln undefined und null unterschiedlich.

Object() konvertiert primitive Werte in Wrapper-Objekte und lässt Objekte unberührt:

> typeof Object('abc')'object'> var obj = {};> Object(obj) === objtrue

It also converts undefined and null to empty objects:

> Object(undefined){}> Object(null){}

In contrast, ToObject() throws a TypeError if it encounters undefined or null. Therefore, the following destructurings fail, even before destructuring accesses any properties:

const { prop: x } = undefined; // TypeErrorconst { prop: y } = null; // TypeError

Daher können Sie das leere Objektmuster {} verwenden, um zu überprüfen, ob ein Wert für ein Objekt erzwungen werden kann. Wie wir gesehen haben, sind nur undefined und null nicht:

({} = ); // OK, Arrays are coercible to objects({} = 'abc'); // OK, strings are coercible to objects({} = undefined); // TypeError({} = null); // TypeError

Die Klammern um die Ausdrücke sind notwendig, da Anweisungen in JavaScript nicht mit geschweiften Klammern beginnen dürfen (Details werden später erläutert).

10.4.2 Array-Muster arbeiten mit Iterablen #

Die Array-Destrukturierung verwendet einen Iterator, um zu den Elementen einer Quelle zu gelangen. Daher können Sie jeden iterierbaren Wert Array-destrukturieren. Schauen wir uns Beispiele für iterierbare Werte an.

Strings sind iterierbar:

const  = 'abc'; // x='a'; y=

Vergessen Sie nicht, dass der Iterator über Zeichenfolgen Codepunkte („Unicode-Zeichen“, 21 Bit) und keine Codeeinheiten („JavaScript-Zeichen“, 16 Bit) zurückgibt. (Weitere Informationen zu Unicode finden Sie im Kapitel „Kapitel 24. Unicode und JavaScript“ in „Speaking JavaScript“.) Zum Beispiel:

const  = 'a\uD83D\uDCA9c'; // x='a'; y='\uD83D\uDCA9'; z='c'

Sie können nicht über Indizes auf die Elemente einer Menge zugreifen, sondern über einen Iterator. Daher funktioniert die Array-Destrukturierung für Mengen:

const  = new Set(); // x='a'; y='b';

Der Iterator Set gibt Elemente immer in der Reihenfolge zurück, in der sie eingefügt wurden, weshalb das Ergebnis der vorherigen Destrukturierung immer dasselbe ist.

10.4.2.1 Fehler bei der Selbstzerstörung eines Werts #

Ein Wert ist iterierbar, wenn er eine Methode hat, deren Schlüssel Symbol.iterator ist, die ein Objekt zurückgibt. Array-Destrukturierung wirft a TypeError wenn der zu destrukturierende Wert nicht iterierbar ist:

let x; = ; // OK, Arrays are iterable = 'abc'; // OK, strings are iterable = { * () { yield 1 } }; // OK, iterable = {}; // TypeError, empty objects are not iterable = undefined; // TypeError, not iterable = null; // TypeError, not iterable

Das TypeError wird bereits vor dem Zugriff auf Elemente des iterable , was bedeutet, dass Sie das leere Array-Muster verwenden können, um zu überprüfen, ob ein Wert iterable:

 = {}; // TypeError, empty objects are not iterable = undefined; // TypeError, not iterable = null; // TypeError, not iterable

10.5 Standardwerte #

Standardwerte sind eine optionale Funktion von Mustern. Sie bieten einen Fallback, wenn in der Quelle nichts gefunden wird. Wenn ein Teil (eine Objekteigenschaft oder ein Array-Element) in der Quelle keine Übereinstimmung aufweist, wird er mit:

  • sein Standardwert (falls angegeben; es ist optional)
  • undefined ( ansonsten)

Schauen wir uns ein Beispiel an. In der folgenden Destrukturierung hat das Element am Index 0 auf der rechten Seite keine Übereinstimmung. Daher wird die Destrukturierung fortgesetzt, indem x mit 3 abgeglichen wird, was dazu führt, dass x auf 3 gesetzt wird.

const  = ; // x = 3; y = undefined

Sie können auch Standardwerte in Objektmustern verwenden:

const {foo: x=3, bar: y} = {}; // x = 3; y = undefined

10.5.1 undefined trigger Standardwerte #

Standardwerte werden auch verwendet, wenn ein Teil eine Übereinstimmung hat und diese Übereinstimmung undefined ist:

const  = ; // x = 1const {prop: y=2} = {prop: undefined}; // y = 2

Die Gründe für dieses Verhalten werden im nächsten Kapitel im Abschnitt Parameterstandardwerte erläutert.

10.5.2 Standardwerte werden bei Bedarf berechnet #

Die Standardwerte selbst werden nur berechnet, wenn sie benötigt werden. Mit anderen Worten, diese Destrukturierung:

const {prop: y=someFunc()} = someValue;

ist äquivalent zu:

let y;if (someValue.prop === undefined) { y = someFunc();} else { y = someValue.prop;}

Sie können beobachten, dass, wenn Sie verwenden console.log():

> function log(x) { console.log(x); return 'YES' }> const = ;> a'YES'> const = ;> b123

In the second destructuring, the default value is not triggered and log() is not called.

10.5.3 Default values can refer to other variables in the pattern #

A default value can refer to any variable, including other variables in the same pattern:

const  = ; // x=3; y=3const  = ; // x=7; y=7const  = ; // x=7; y=2

Ordnung ist jedoch wichtig: die Variablen x und y werden von links nach rechts deklariert und erzeugen ein ReferenceError, wenn auf sie vor ihren Deklarationen zugegriffen wird:

const  = ; // ReferenceError

10.5.4 Standardwerte für Muster #

Bisher haben wir nur Standardwerte für Variablen gesehen, aber Sie können sie auch mit Mustern verknüpfen:

const  = ;

Was bedeutet das? Rufen Sie die Regel für Standardwerte auf: Wenn ein Teil in der Quelle keine Übereinstimmung aufweist, wird die Destrukturierung mit dem Standardwert fortgesetzt.

Das Element am Index 0 hat keine Übereinstimmung, weshalb die Destrukturierung mit fortgesetzt wird:

const { prop: x } = {}; // x = undefined

Sie können leichter erkennen, warum die Dinge so funktionieren, wenn Sie das Muster { prop: x } durch die Variable ersetzen pattern:

const  = ;

10.5.5 Komplexere Standardwerte #

Lassen Sie uns die Standardwerte für Muster weiter untersuchen. Im folgenden Beispiel weisen wir x einen Wert über den Standardwert { prop: 123 } zu:

const  = ;

Da das Array-Element am Index 0 auf der rechten Seite keine Übereinstimmung aufweist, wird die Destrukturierung wie folgt fortgesetzt und x auf 123 gesetzt.

const { prop: x } = { prop: 123 }; // x = 123

x wird auf diese Weise jedoch kein Wert zugewiesen, wenn die rechte Seite ein Element am Index 0 hat, da dann der Standardwert nicht ausgelöst wird.

const  = ;

In diesem Fall wird die Destrukturierung fortgesetzt mit:

const { prop: x } = {}; // x = undefined

Wenn also x 123 sein soll, wenn entweder das Objekt oder die Eigenschaft fehlt, müssen Sie einen Standardwert für x selbst angeben:

const  = ;

Dabei wird die Destrukturierung wie folgt fortgesetzt, unabhängig davon, ob die rechte Seite oder ist.

const { prop: x=123 } = {}; // x = 123

10.6 Weitere Funktionen zur Objektdestrukturierung #

10.6.1 Eigenschaftswert-Shorthands #

Eigenschaftswert-Shorthands sind eine Funktion von Objektliteralen: Wenn der Eigenschaftswert eine Variable ist, die denselben Namen wie der Eigenschaftsschlüssel hat, können Sie den Schlüssel weglassen. Dies funktioniert auch für die Destrukturierung:

const { x, y } = { x: 11, y: 8 }; // x = 11; y = 8// Same as:const { x: x, y: y } = { x: 11, y: 8 };

Sie können Eigenschaftswertkürzel auch mit Standardwerten kombinieren:

const { x, y = 1 } = {}; // x = undefined; y = 1

10.6.2 Berechnete Eigenschaftsschlüssel #

Berechnete Eigenschaftsschlüssel sind ein weiteres Objektliteral-Feature, das auch für die Destrukturierung geeignet ist. Sie können den Schlüssel einer Eigenschaft über einen Ausdruck angeben, wenn Sie ihn in eckige Klammern setzen:

const FOO = 'foo';const { : f } = { foo: 123 }; // f = 123

Mit berechneten Eigenschaftsschlüsseln können Sie Eigenschaften zerstören, deren Schlüssel Symbole sind:

// Create and destructure a property whose key is a symbolconst KEY = Symbol();const obj = { : 'abc' };const { : x } = obj; // x = 'abc'// Extract Array.prototypeconst { : func } = ;console.log(typeof func); // function

10.7 Weitere Funktionen zur Array-Destrukturierung #

10.7.1 Elision #

Mit Elision können Sie die Syntax von Array- „Löchern“ verwenden, um Elemente während der Destrukturierung zu überspringen:

const  = ; // x = 'c'; y = 'd'

10.7.2 Rest-Operator (...) #

Mit dem Rest-Operator können Sie die verbleibenden Elemente eines Iterable in ein Array extrahieren. Wenn dieser Operator in einem Array-Muster verwendet wird, muss er als letzter kommen:

const  = ; // x='a'; y=

Wenn der Operator keine Elemente finden kann, vergleicht er seinen Operanden mit dem leeren Array. Das heißt, es erzeugt niemals undefined oder null . Zum Beispiel:

const  = ; // x='a'; y=undefined; z=

Der Operand des Rest-Operators muss keine Variable sein, Sie können auch Muster verwenden:

const ] = ; // x = 'a'; y = 'b'; z = 'c'

Der Rest-Operator löst die folgende Destrukturierung aus:

 = 

10.8 Sie können mehr als nur Variablen zuweisen #

Wenn Sie über Destrukturierung zuweisen, kann jedes Zuweisungsziel alles sein, was auf der linken Seite einer normalen Zuweisung zulässig ist.

Zum Beispiel ein Verweis auf eine Eigenschaft (obj.prop):

const obj = {};({ foo: obj.prop } = { foo: 123 });console.log(obj); // {prop:123}

Oder ein Verweis auf ein Array-Element (arr):

const arr = ;({ bar: arr } = { bar: true });console.log(arr); // 

Sie können Objekteigenschaften und Array-Elementen auch über den Rest-Operator zuweisen (...):

const obj = {}; = ; // first = 'a'; obj.prop = 

Wenn Sie Variablen deklarieren oder Parameter über Destrukturierung definieren, müssen Sie einfache Bezeichner verwenden.

10.9 Fallstricke der Destrukturierung #

Bei der Verwendung der Destrukturierung sind zwei Dinge zu beachten:

  • Sie können eine Anweisung nicht mit einer geschweiften Klammer beginnen.
  • Während der Destrukturierung können Sie entweder Variablen deklarieren oder ihnen zuweisen, aber nicht beides.

Die nächsten beiden Abschnitte enthalten die Details.

10.9.1 Beginnen Sie eine Anweisung nicht mit einer geschweiften Klammer #

Da Codeblöcke mit einer geschweiften Klammer beginnen, dürfen Anweisungen nicht mit einer beginnen. Dies ist bedauerlich, wenn die Objektdestrukturierung in einer Zuweisung verwendet wird:

{ a, b } = someObject; // SyntaxError

Die Problemumgehung besteht darin, den vollständigen Ausdruck in Klammern zu setzen:

({ a, b } = someObject); // OK

Die folgende Syntax funktioniert nicht:

({ a, b }) = someObject; // SyntaxError

Mit let, var und const verursachen geschweifte Klammern niemals Probleme:

const { a, b } = someObject; // OK

10.10 Beispiele für Destrukturierung #

Beginnen wir mit ein paar kleineren Beispielen.

Die for-of-Schleife unterstützt die Destrukturierung:

const map = new Map().set(false, 'no').set(true, 'yes');for (const  of map) { console.log(key + ' is ' + value);}

Sie können die Destrukturierung verwenden, um Werte auszutauschen. Das ist etwas, das Engines optimieren könnten, so dass kein Array erstellt würde.

 = ;

Sie können die Destrukturierung verwenden, um ein Array aufzuteilen:

const  = ; // first = 'a'; rest = 

10.10.1 #

Einige integrierte JavaScript-Operationen geben Arrays zurück. Destrukturierung hilft bei der Verarbeitung:

const  = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec('2999-12-31');

Wenn Sie nur an den Gruppen interessiert sind (und nicht an der vollständigen Übereinstimmung all ), können Sie mit elision das Array-Element am index überspringen 0:

const  = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec('2999-12-31');

exec() gibt null zurück, wenn der reguläre Ausdruck nicht übereinstimmt. Leider können Sie null nicht über Standardwerte verarbeiten, weshalb Sie in diesem Fall den Operator Or (||) verwenden müssen:

const  = /^(\d\d\d\d)-(\d\d)-(\d\d)$/ .exec(someStr) || ;

Array.prototype.split() gibt ein Array zurück. Daher ist die Destrukturierung nützlich, wenn Sie an den Elementen und nicht am Array interessiert sind:

const cells = 'Jane\tDoe\tCTO'const  = cells.split('\t');console.log(firstName, lastName, title);

10.10.2 #

Die Destrukturierung ist auch nützlich, um Daten aus Objekten zu extrahieren, die von Funktionen oder Methoden zurückgegeben werden. Beispielsweise gibt die Iteratormethode next() ein Objekt mit zwei Eigenschaften zurück, done und value. Der folgende Code protokolliert alle Elemente des Arrays arr über den Iterator iter. Destrukturierung wird in Zeile A verwendet.

const arr = ;const iter = arr();while (true) { const {done,value} = iter.next(); // (A) if (done) break; console.log(value);}

10.10.3 Array-Destrukturierung iterierbare Werte #

Array-Destrukturierung funktioniert mit jedem iterierbaren Wert. Das ist gelegentlich nützlich:

const  = new Set().add('a').add('b'); // x = 'a'; y = 'b'const  = 'foo'; // a = 'f'; b = 'o'

10.10.4 Mehrere Rückgabewerte #

Um die Nützlichkeit mehrerer Rückgabewerte zu ermitteln, implementieren wir eine Funktion findElement(a, p), die nach dem ersten Element im Array a sucht, für das die Funktion p true zurückgibt. Die Frage ist: Was soll findElement() zurückgeben? Manchmal interessiert man sich für das Element selbst, manchmal für seinen Index, manchmal für beides. Die folgende Implementierung gibt beide zurück.

function findElement(array, predicate) { for (const  of array.entries()) { // (A) if (predicate(element, index, array)) { // We found an element: return { element, index }; // Same as (property value shorthands): // { element: element, index: index } } } // We couldn't find anything; return failure values: return { element: undefined, index: -1 };}

Die Funktion iteriert über alle Elemente von array über die Array-Methode entries() , die ein iterierbares über Paare (Zeile A) zurückgibt. Auf die Teile der Paare wird über Destrukturierung zugegriffen.

Verwenden wir findElement():

const arr = ;const {element, index} = findElement(arr, x => x % 2 === 0); // element = 8, index = 1

Mehrere ECMAScript 6-Funktionen ermöglichten es uns, prägnanteren Code zu schreiben: Der Rückruf ist eine Pfeilfunktion; Der Rückgabewert wird über ein Objektmuster mit Eigenschaftswertkürzeln destrukturiert.

Da index und element sich auch auf Eigenschaftsschlüssel beziehen, spielt die Reihenfolge, in der wir sie erwähnen, keine Rolle. Wir können sie tauschen und nichts ändert sich:

const {index, element} = findElement(···);

Wir haben den Fall, dass sowohl Index als auch Element benötigt werden, erfolgreich behandelt. Was ist, wenn wir nur an einem von ihnen interessiert sind? Es stellt sich heraus, dass unsere Implementierung dank ECMAScript 6 auch dafür sorgen kann. Und der syntaktische Overhead im Vergleich zu Funktionen mit einzelnen Rückgabewerten ist minimal.

const a = ;const {element} = findElement(a, x => x % 2 === 0); // element = 8const {index} = findElement(a, x => x % 2 === 0); // index = 1

Jedes Mal extrahieren wir nur den Wert der einen Eigenschaft, die wir benötigen.

10.11 Der Destrukturierungsalgorithmus #

In diesem Abschnitt wird die Destrukturierung aus einem anderen Blickwinkel betrachtet: als rekursiver Mustervergleichsalgorithmus.

Am Ende werde ich den Algorithmus verwenden, um den Unterschied zwischen den folgenden beiden Funktionsdeklarationen zu erklären.

function move({x=0, y=0} = {}) { ··· }function move({x, y} = { x: 0, y: 0 }) { ··· }

10.11.1 Der Algorithmus #

Eine Destrukturierungszuweisung sieht folgendermaßen aus:

"pattern" = "value"

Wir möchten pattern verwenden, um Daten aus value zu extrahieren. Dazu beschreibe ich nun einen Algorithmus, der in der funktionalen Programmierung als Pattern Matching (kurz: Matching) bekannt ist. Der Algorithmus gibt den Operator („match against“) für die Destrukturierungszuweisung an, der a pattern mit a value vergleicht und dabei Variablen zuweist:

"pattern"  "value"

Der Algorithmus wird über rekursive Regeln spezifiziert, die beide Operanden des Operators auseinandernehmen. Die deklarative Notation mag gewöhnungsbedürftig sein, macht aber die Spezifikation des Algorithmus prägnanter. Jede Regel besteht aus zwei Teilen:

  • Der Kopf (erste Zeile) beschreibt die Bedingung, die die Regel auslöst.
  • Der Hauptteil (verbleibende Zeilen) beschreibt, was passiert, wenn die Regel ausgelöst wird.

Schauen wir uns ein Beispiel an:

  • ( 2c) {key: "pattern", "properties"} ← obj
     "pattern"  obj.key {"properties"}  obj
  • ( 2e) {} ← obj (keine Eigenschaften mehr vorhanden)
     // Nothing to do

In Regel (2c) bedeutet der Kopf, dass diese Regel ausgeführt wird, wenn ein Objektmuster mit mindestens einer Eigenschaft und null oder mehr verbleibenden Eigenschaften vorhanden ist. Dieses Muster wird mit einem Wert obj abgeglichen. Diese Regel bewirkt, dass die Ausführung fortgesetzt wird, wobei das Eigenschaftswertmuster mit obj.key und die verbleibenden Eigenschaften mit obj abgeglichen werden.

In Regel (2e)bedeutet der Kopf, dass diese Regel ausgeführt wird, wenn das leere Objektmuster {} mit einem Wert obj abgeglichen wird. Dann gibt es nichts zu tun.

Wenn der Algorithmus aufgerufen wird, werden die Regeln von oben nach unten überprüft und nur die erste Regel ausgeführt, die anwendbar ist.

Ich zeige nur den Algorithmus für die Destrukturierungszuweisung. Destrukturierende Variablendeklarationen und destrukturierende Parameterdefinitionen funktionieren ähnlich.

Ich behandle keine erweiterten Funktionen (berechnete Eigenschaftsschlüssel; Eigenschaftswertkürzel; b. Objekteigenschaften und Array-Elemente als Zuweisungsziele). Nur die Grundlagen.

10.11.1.1 Muster #

Ein Muster ist entweder:

  • Eine Variable: x
  • Ein Objektmuster: {"properties"}
  • Ein Array-Muster:

Jeder der folgenden Abschnitte beschreibt einen dieser drei Fälle.

Die folgenden drei Abschnitte geben an, wie diese drei Fälle behandelt werden. Jeder Abschnitt enthält eine oder mehrere nummerierte Regeln.

10.11.1.2 Variabel #
  • (1) x ← value ( einschließlich undefined und null)
     x = value
10.11.1.3 Objekt muster #
  • ( 2a) {"properties"} ← undefined
     throw new TypeError();
  • ( 2b) {"properties"} ← null
     throw new TypeError();
  • ( 2c) {key: "pattern", "properties"} ← obj
     "pattern"  obj.key {"properties"}  obj
  • ( 2d) {key: "pattern" = default_value, "properties"} ← obj
     const tmp = obj.key; if (tmp !== undefined) { "pattern"  tmp } else { "pattern"  default_value } {"properties"}  obj
  • ( 2e) {} ← obj (keine Eigenschaften mehr vorhanden)
     // Nothing to do
10.11.1.4 Array-Muster #

Array-Muster und iterierbar. Der Algorithmus für die Array-Destrukturierung beginnt mit einem Array-Muster und einem iterierbaren:

  • ( 3a) ← non_iterable
    assert(!isIterable(non_iterable))
     throw new TypeError();
  • ( 3b) ← iterable
    assert(isIterable(iterable))
     const iterator = iterable(); "elements"  iterator

Helfer funktion:

function isIterable(value) { return (value !== null && typeof value === 'object' && typeof value === 'function');}

Array-Elemente und Iterator. Der Algorithmus fährt mit den Elementen des Musters (linke Seite des Pfeils) und dem Iterator fort, der aus dem Iterierbaren (rechte Seite des Pfeils) erhalten wurde.

  • ( 3c) "pattern", "elements" ← iterator
     "pattern"  getNext(iterator) // undefined after last item "elements"  iterator
  • ( 3d) "pattern" = default_value, "elements" ← iterator
     const tmp = getNext(iterator); // undefined after last item if (tmp !== undefined) { "pattern"  tmp } else { "pattern"  default_value } "elements"  iterator
  • ( 3e) , "elements" ← iterator (loch, Elision)
     getNext(iterator); // skip "elements"  iterator
  • ( 3f) ..."pattern" ← iterator (immer letzter Teil!)
     const tmp = ; for (const elem of iterator) { tmp.push(elem); } "pattern"  tmp
  • ( 3g) ← iterator (keine Elemente mehr vorhanden)
     // Nothing to do

Helfer funktion:

function getNext(iterator) { const {done,value} = iterator.next(); return (done ? undefined : value);}

10.11.2 Wenn Sie den Algorithmus #

In ECMAScript 6 anwenden, können Sie benannte Parameter simulieren, wenn der Aufrufer ein Objektliteral verwendet und der Angerufene die Destrukturierung verwendet. Diese Simulation wird im Kapitel Parameterhandhabung ausführlich erläutert. Der folgende Code zeigt ein Beispiel: Die Funktion move1() hat zwei benannte Parameter, x und y:

function move1({x=0, y=0} = {}) { // (A) return ;}move1({x: 3, y: 8}); // move1({x: 3}); // move1({}); // move1(); // 

In Zeile A gibt es drei Standardwerte:

  • Mit den ersten beiden Standardwerten können Sie x und y weglassen.
  • Mit dem dritten Standardwert können Sie move1() ohne Parameter aufrufen (wie in der letzten Zeile).

Aber warum würden Sie die Parameter wie im vorherigen Codeausschnitt definieren? Warum nicht wie folgt – das ist auch völlig legal ES6-Code?

function move2({x, y} = { x: 0, y: 0 }) { return ;}

Um zu sehen, warum move1() korrekt ist, verwenden wir beide Funktionen für zwei Beispiele. Bevor wir das tun, wollen wir sehen, wie die Übergabe von Parametern über Matching erklärt werden kann.

10.11.2.1 Hintergrund: Übergeben von Parametern über matching #

Bei Funktionsaufrufen werden formale Parameter (innerhalb von Funktionsdefinitionen) mit tatsächlichen Parametern (innerhalb von Funktionsaufrufen) abgeglichen. Nehmen Sie als Beispiel die folgende Funktionsdefinition und den folgenden Funktionsaufruf.

function func(a=0, b=0) { ··· }func(1, 2);

Die Parameter a und b werden ähnlich wie bei der folgenden Destrukturierung eingerichtet.

  
10.11.2.2 Verwenden move2() #

Lassen Sie uns untersuchen, wie die Destrukturierung für move2() funktioniert.

Beispiel 1. move2() führt zu dieser Destrukturierung:

  

Das einzelne Array-Element auf der linken Seite hat keine Übereinstimmung auf der rechten Seite, weshalb {x,y} mit dem Standardwert und nicht mit Daten von der rechten Seite abgeglichen wird (Regeln 3b, 3d):

{x, y}  { x: 0, y: 0 }

Die linke Seite enthält Eigenschaftswertkürzel, es ist eine Abkürzung für:

{x: x, y: y}  { x: 0, y: 0 }

Diese Destrukturierung führt zu den folgenden zwei Zuweisungen (Regeln 2c, 1):

x = 0;y = 0;

Beispiel 2. Untersuchen wir den Funktionsaufruf move2({z:3}), der zur folgenden Destrukturierung führt:

  

Auf der rechten Seite befindet sich ein Array-Element am Index 0. Daher wird der Standardwert ignoriert und der nächste Schritt ist (Regel 3d):

{x, y}  { z: 3 }

Das führt dazu, dass sowohl x als auch y auf undefined gesetzt werden, was nicht das ist, was wir wollen.

10.11.2.3 Verwenden move1() #

Versuchen wir move1() .

Beispiel 1: move1()

  

Wir haben kein Array-Element am Index 0 auf der rechten Seite und verwenden den Standardwert (Regel 3d):

{x=0, y=0}  {}

Die linke Seite enthält Eigenschaftswertkürzel, was bedeutet, dass diese Destrukturierung äquivalent ist zu:

{x: x=0, y: y=0}  {}

Weder Eigenschaft x noch Eigenschaft y haben eine Übereinstimmung auf der rechten Seite. Daher werden die Standardwerte verwendet und die folgenden Destrukturen werden als nächstes ausgeführt (Regel 2d):

x  0y  0

Das führt zu folgenden Zuweisungen (Regel 1):

x = 0y = 0

Beispiel 2: move1({z:3})

  

Das erste Element des Array-Musters hat eine Übereinstimmung auf der rechten Seite und diese Übereinstimmung wird verwendet, um die Destrukturierung fortzusetzen (Regel 3d):

{x=0, y=0}  {z:3}

Wie in Beispiel 1 gibt es auf der rechten Seite keine Eigenschaften x und y und es werden die Standardwerte verwendet:

x = 0y = 0
10.11.2.4 Fazit #

Die Beispiele zeigen, dass Standardwerte ein Merkmal von Musterteilen (Objekteigenschaften oder Array-Elementen) sind. Wenn ein Teil keine Übereinstimmung hat oder mit undefined übereinstimmt, wird der Standardwert verwendet. Das heißt, das Muster wird stattdessen mit dem Standardwert abgeglichen.