10. Destrukturierung
Inhaltsverzeichnis
Bitte unterstützen Sie dieses Buch: kaufen Sie es (PDF, EPUB, MOBI) oder spenden Sie
(Werbung, bitte nicht blockieren.)

10. Destrukturierung



10.1 Überblick

Destrukturierung ist eine bequeme Methode, um mehrere Werte aus Daten zu extrahieren, die in (möglicherweise verschachtelten) Objekten und Arrays gespeichert sind. Sie kann an Orten verwendet werden, die Daten empfangen (wie die linke Seite einer Zuweisung). Wie die Werte extrahiert werden, wird durch Muster angegeben (lesen Sie weiter für Beispiele).

10.1.1 Objekt-Destrukturierung

Objekte destrukturieren

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 = ['a', 'b'];
const [x, y] = iterable;
    // x = 'a'; y = 'b'

Destrukturierung hilft bei der Verarbeitung von Rückgabewerten

const [all, year, month, day] =
    /^(\d\d\d\d)-(\d\d)-(\d\d)$/
    .exec('2999-12-31');

10.1.3 Wo kann Destrukturierung verwendet werden?

Destrukturierung kann an folgenden Stellen verwendet werden (ich zeige Array-Muster zur Veranschaulichung; Objektmuster funktionieren genauso gut)

// Variable declarations:
const [x] = ['a'];
let [x] = ['a'];
var [x] = ['a'];

// Assignments:
[x] = ['a'];

// Parameter definitions:
function f([x]) { ··· }
f(['a']);

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

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

10.2 Hintergrund: Daten konstruieren versus Daten extrahieren

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

JavaScript verfügt über Operationen zum Konstruieren von Daten, eine Eigenschaft nach der anderen

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;

Zusätzlich gibt es eine Syntax zum gleichzeitigen Konstruieren mehrerer Eigenschaften über ein Objektliteral

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

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

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

Sie können auch Arrays über Muster destrukturieren

const [x, y] = ['a', 'b']; // x = 'a'; y = 'b'

10.3 Muster für die Destrukturierung

Die folgenden beiden Parteien sind an der Destrukturierung beteiligt

Das Destrukturierungsziel ist eines von drei Mustern

Das bedeutet, dass Sie Muster beliebig tief verschachteln können

const obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
const { a: [{foo: f}] } = obj; // f = 123

10.3.1 Wählen Sie aus, was Sie benötigen

Wenn Sie ein Objekt destrukturieren, erwähnen Sie nur die Eigenschaften, an denen Sie interessiert sind

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

Wenn Sie ein Array destrukturieren, können Sie wählen, nur ein Präfix zu extrahieren

const [x,y] = ['a', 'b', 'c']; // x='a'; y='b';

10.4 Wie greifen Muster auf den Inhalt von Werten zu?

Bei einer Zuweisung muster = someValue, wie greift muster auf das Innere von someValue zu?

10.4.1 Objektmuster zwangsweise in Objekte umwandeln

Das Objektmuster wandelt Destrukturierungsquellen vor dem Zugriff auf Eigenschaften zwangsweise in Objekte um. Das bedeutet, dass es mit primitiven Werten funktioniert

const {length : len} = 'abc'; // len = 3
const {toString: s} = 123; // s = Number.prototype.toString
10.4.1.1 Fehler bei der Objekt-Destrukturierung eines Wertes

Die Umwandlung in ein Objekt erfolgt nicht über Object(), sondern über die interne Operation ToObject(). Die beiden Operationen behandeln undefined und null unterschiedlich.

Object() konvertiert primitive Werte in Wrapper-Objekte und lässt Objekte unverändert

> typeof Object('abc')
'object'

> var obj = {};
> Object(obj) === obj
true

Es konvertiert auch undefined und null in leere Objekte

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

Im Gegensatz dazu wirft ToObject() einen TypeError, wenn es auf undefined oder null trifft. Daher schlagen die folgenden Destrukturierungen fehl, noch bevor die Destrukturierung auf Eigenschaften zugreift

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

Infolgedessen können Sie das leere Objektmuster {} verwenden, um zu überprüfen, ob ein Wert in ein Objekt umgewandelt werden kann. Wie wir gesehen haben, sind nur undefined und null nicht umwandelbar

({} = [true, false]); // 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 erklärt).

10.4.2 Array-Muster arbeiten mit Iterables

Array-Destrukturierung verwendet einen Iterator, um zu den Elementen einer Quelle zu gelangen. Daher können Sie jeden iterierbaren Wert mit Array-Destrukturierung verarbeiten. Betrachten wir Beispiele für iterierbare Werte.

Strings sind iterierbar

const [x,...y] = 'abc'; // x='a'; y=['b', 'c']

Vergessen Sie nicht, dass der Iterator über Strings Code-Punkte („Unicode-Zeichen“, 21 Bit) zurückgibt, nicht Code-Einheiten („JavaScript-Zeichen“, 16 Bit). (Weitere Informationen zu Unicode finden Sie im Kapitel „Kapitel 24. Unicode und JavaScript“ in „Speaking JavaScript“.) Zum Beispiel

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

Sie können nicht über Indizes auf die Elemente eines Sets zugreifen, aber Sie können dies über einen Iterator tun. Daher funktioniert Array-Destrukturierung für Sets

const [x,y] = new Set(['a', 'b']); // x='a'; y='b’;

Der Set-Iterator 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 Array-Destrukturierung eines Wertes

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

let x;
[x] = [true, false]; // OK, Arrays are iterable
[x] = 'abc'; // OK, strings are iterable
[x] = { * [Symbol.iterator]() { yield 1 } }; // OK, iterable

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

Der TypeError wird bereits vor dem Zugriff auf Elemente des Iterables ausgelöst, was bedeutet, dass Sie das leere Array-Muster [] verwenden können, um zu überprüfen, ob ein Wert iterierbar ist

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

10.5 Standardwerte

Standardwerte sind ein optionales Merkmal von Mustern. Sie bieten einen Fallback, wenn nichts in der Quelle gefunden wird. Wenn ein Teil (eine Objekteigenschaft oder ein Array-Element) keine Übereinstimmung in der Quelle hat, wird er abgeglichen gegen

Betrachten wir ein Beispiel. In der folgenden Destrukturierung hat das Element am Index 0 keine Übereinstimmung auf der rechten Seite. 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] = []; // x = 3; y = undefined

Sie können Standardwerte auch in Objektmustern verwenden

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

10.5.1 undefined löst Standardwerte aus

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

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

Die Begründung für dieses Verhalten wird im nächsten Kapitel erläutert, in der Sektion über Standardparameterwerte.

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;

entspricht

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

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

> function log(x) { console.log(x); return 'YES' }

> const [a=log('hello')] = [];
> a
'YES'

> const [b=log('hello')] = [123];
> b
123

Bei der zweiten Destrukturierung wird der Standardwert nicht ausgelöst und log() wird nicht aufgerufen.

10.5.3 Standardwerte können auf andere Variablen im Muster verweisen

Ein Standardwert kann auf jede Variable verweisen, einschließlich anderer Variablen im selben Muster

const [x=3, y=x] = [];     // x=3; y=3
const [x=3, y=x] = [7];    // x=7; y=7
const [x=3, y=x] = [7, 2]; // x=7; y=2

Die Reihenfolge ist jedoch wichtig: Die Variablen x und y werden von links nach rechts deklariert und erzeugen einen ReferenceError, wenn auf sie zugegriffen wird, bevor ihre Deklarationen erfolgen

const [x=y, y=3] = []; // ReferenceError

10.5.4 Standardwerte für Muster

Bisher haben wir nur Standardwerte für Variablen gesehen, aber Sie können sie auch Mustern zuordnen

const [{ prop: x } = {}] = [];

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

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

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

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

const [pattern = {}] = [];

10.5.5 Komplexere Standardwerte

Erkunden wir Standardwerte für Muster weiter. Im folgenden Beispiel weisen wir x über den Standardwert { prop: 123 } zu

const [{ prop: x } = { prop: 123 }] = [];

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

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

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

const [{ prop: x } = { prop: 123 }] = [{}];

In diesem Fall wird die Destrukturierung fortgesetzt mit

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

Wenn Sie also möchten, dass x 123 ist, wenn entweder das Objekt oder die Eigenschaft fehlt, müssen Sie x selbst einen Standardwert zuweisen

const [{ prop: x=123 } = {}] = [{}];

Hier wird die Destrukturierung wie folgt fortgesetzt, unabhängig davon, ob die rechte Seite [{}] oder [] ist.

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

10.6 Weitere Features der Objekt-Destrukturierung

10.6.1 Kurzformen für Eigenschaftswerte

Kurzformen für Eigenschaftswerte sind ein Merkmal 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 bei der 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 Kurzformen für Eigenschaftswerte auch mit Standardwerten kombinieren

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

10.6.2 Berechnete Eigenschaftsschlüssel

Berechnete Eigenschaftsschlüssel sind ein weiteres Merkmal von Objektliteralen, das auch bei der Destrukturierung funktioniert. Sie können den Schlüssel einer Eigenschaft über einen Ausdruck angeben, wenn Sie ihn in eckige Klammern setzen

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

Berechnete Eigenschaftsschlüssel ermöglichen es Ihnen, Eigenschaften zu destrukturieren, deren Schlüssel Symbole sind

// Create and destructure a property whose key is a symbol
const KEY = Symbol();
const obj = { [KEY]: 'abc' };
const { [KEY]: x } = obj; // x = 'abc'

// Extract Array.prototype[Symbol.iterator]
const { [Symbol.iterator]: func } = [];
console.log(typeof func); // function

10.7 Weitere Features der Array-Destrukturierung

10.7.1 Elision

Elision ermöglicht es Ihnen, die Syntax von Array-"Löchern" zu verwenden, um Elemente während der Destrukturierung zu überspringen

const [,, x, y] = ['a', 'b', 'c', 'd']; // x = 'c'; y = 'd'

10.7.2 Rest-Operator (...)

Der Rest-Operator ermöglicht es Ihnen, die verbleibenden Elemente eines Iterables in einem Array zu extrahieren. Wenn dieser Operator in einem Array-Muster verwendet wird, muss er am Ende stehen

const [x, ...y] = ['a', 'b', 'c']; // x='a'; y=['b', 'c']

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

const [x, y, ...z] = ['a']; // x='a'; y=undefined; z=[]

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

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

Der Rest-Operator löst folgende Destrukturierung aus

[y, z] = ['b', 'c']

10.8 Sie können mehr zuweisen als nur Variablen

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

Zum Beispiel eine Referenz auf eine Eigenschaft (obj.prop)

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

Oder eine Referenz auf ein Array-Element (arr[0])

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

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

const obj = {};
[first, ...obj.prop] = ['a', 'b', 'c'];
    // first = 'a'; obj.prop = ['b', 'c']

Wenn Sie Variablen deklarieren oder Parameter per Destrukturierung definieren, müssen Sie einfache Bezeichner verwenden, Sie können nicht auf Objekteigenschaften und Array-Elemente verweisen.

10.9 Fallstricke der Destrukturierung

Es gibt zwei Dinge, die Sie bei der Verwendung von Destrukturierung beachten sollten

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. Das ist unglücklich, wenn man Objekt-Destrukturierung in einer Zuweisung verwendet

{ a, b } = someObject; // SyntaxError

Die Umgehung besteht darin, den gesamten 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 nie 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 Destrukturierung

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

Sie können Destrukturierung verwenden, um Werte zu vertauschen. Das ist etwas, das Engines optimieren könnten, sodass kein Array erstellt wird.

[a, b] = [b, a];

Sie können Destrukturierung verwenden, um ein Array aufzuteilen

const [first, ...rest] = ['a', 'b', 'c'];
    // first = 'a'; rest = ['b', 'c']

10.10.1 Rückgabewerte von Arrays destrukturieren

Einige eingebaute JavaScript-Operationen geben Arrays zurück. Destrukturierung hilft bei deren Verarbeitung

const [all, year, month, day] =
    /^(\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 Elision verwenden, um das Array-Element an Index 0 zu überspringen

const [, year, month, day] =
    /^(\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 mit Standardwerten behandeln, weshalb Sie in diesem Fall den Oder-Operator (||) verwenden müssen

const [, year, month, day] =
    /^(\d\d\d\d)-(\d\d)-(\d\d)$/
    .exec(someStr) || [];

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

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

10.10.2 Rückgabewerte von Objekten destrukturieren

Destrukturierung ist auch nützlich zum Extrahieren von Daten aus Objekten, die von Funktionen oder Methoden zurückgegeben werden. Zum Beispiel gibt die Iterator-Methode 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 = ['a', 'b'];
const iter = arr[Symbol.iterator]();
while (true) {
    const {done,value} = iter.next(); // (A)
    if (done) break;
    console.log(value);
}

10.10.3 Iterierbare Werte mit Array-Destrukturierung

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

const [x,y] = new Set().add('a').add('b');
    // x = 'a'; y = 'b'

const [a,b] = 'foo';
    // a = 'f'; b = 'o'

10.10.4 Mehrere Rückgabewerte

Um die Nützlichkeit mehrerer Rückgabewerte zu sehen, 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 sollte findElement() zurückgeben? Manchmal ist man am Element selbst interessiert, manchmal an seinem Index, manchmal an beidem. Die folgende Implementierung gibt beides zurück.

function findElement(array, predicate) {
    for (const [index, element] 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 des array, über die Array-Methode entries(), die ein Iterable über [index,element]-Paare zurückgibt (Zeile A). Die Teile der Paare werden per Destrukturierung abgerufen.

Verwenden wir findElement()

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

Mehrere ECMAScript 6-Features ermöglichten es uns, prägnanteren Code zu schreiben: Der Callback ist eine Pfeilfunktion; der Rückgabewert wird per Objektmuster mit Kurzformen für Eigenschaftswerte 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 vertauschen und nichts ändert sich

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

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

const a = [7, 8, 6];

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

const {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

Dieser Abschnitt betrachtet die Destrukturierung aus einem anderen Blickwinkel: als rekursiven Musterabgleichalgorithmus.

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 so aus

«pattern» = «value»

Wir möchten muster verwenden, um Daten aus wert zu extrahieren. Ich werde nun einen Algorithmus dafür beschreiben, der in der funktionalen Programmierung als Musterabgleich (kurz: Abgleich) bekannt ist. Der Algorithmus spezifiziert den Operator („abgleichen mit“) für Destrukturierungszuweisungen, der ein muster mit einem wert abgleicht und dabei Variablen zuweist

«pattern»  «value»

Der Algorithmus wird über rekursive Regeln spezifiziert, die beide Operanden des -Operators zerlegen. Die deklarative Notation mag gewöhnungsbedürftig sein, macht aber die Spezifikation des Algorithmus prägnanter. Jede Regel hat zwei Teile

Betrachten wir ein Beispiel

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. Die Auswirkung dieser Regel ist, dass die Ausführung mit dem Muster des Eigenschaftswerts, das mit obj.key abgeglichen wird, und den verbleibenden Eigenschaften, die mit obj abgeglichen werden, fortgesetzt wird.

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.

Immer wenn der Algorithmus aufgerufen wird, werden die Regeln von oben nach unten geprüft und nur die erste anwendbare Regel wird ausgeführt.

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

Ich behandle auch keine fortgeschrittenen Features (berechnete Eigenschaftsschlüssel; Kurzformen für Eigenschaftswerte; Objekteigenschaften und Array-Elemente als Zuweisungsziele). Nur die Grundlagen.

10.11.1.1 Muster

Ein Muster ist entweder

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

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

10.11.1.2 Variable
10.11.1.3 Objektmuster
10.11.1.4 Array-Muster

Array-Muster und Iterable. Der Algorithmus für die Array-Destrukturierung beginnt mit einem Array-Muster und einem Iterable

Hilfsfunktion

function isIterable(value) {
    return (value !== null
        && typeof value === 'object'
        && typeof value[Symbol.iterator] === 'function');
}

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

Hilfsfunktion

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

10.11.2 Anwenden des Algorithmus

In ECMAScript 6 können Sie benannte Parameter simulieren, wenn der Aufrufer ein Objektliteral verwendet und der Aufgerufene Destrukturierung verwendet. Diese Simulation wird im Detail im Kapitel zur Parameterbehandlung 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 [x, y];
}
move1({x: 3, y: 8}); // [3, 8]
move1({x: 3}); // [3, 0]
move1({}); // [0, 0]
move1(); // [0, 0]

Es gibt drei Standardwerte in Zeile A

Aber warum würden Sie die Parameter wie im vorherigen Code-Snippet definieren? Warum nicht wie folgt – was ebenfalls völlig legaler ES6-Code ist?

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

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

10.11.2.1 Hintergrund: Parameterübergabe durch Abgleich

Für Funktionsaufrufe werden formale Parameter (innerhalb von Funktionsdefinitionen) mit tatsächlichen Parametern (innerhalb von Funktionsaufrufen) abgeglichen. Als Beispiel nehmen wir die folgende Funktionsdefinition und den folgenden Funktionsaufruf.

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

Die Parameter a und b sind ähnlich wie die folgende Destrukturierung eingerichtet.

[a=0, b=0]  [1, 2]
10.11.2.2 Verwendung von move2()

Betrachten wir, wie die Destrukturierung für move2() funktioniert.

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

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

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 Kurzformen für Eigenschaftswerte, sie ist eine Abkürzung für

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

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

x = 0;
y = 0;

Beispiel 2. Betrachten wir den Funktionsaufruf move2({z:3}), der zu folgender Destrukturierung führt

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

Es gibt ein Array-Element am Index 0 auf der rechten Seite. 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 Verwendung von move1()

Versuchen wir es mit move1().

Beispiel 1: move1()

[{x=0, y=0} = {}]  []

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

{x=0, y=0}  {}

Die linke Seite enthält Kurzformen für Eigenschaftswerte, was bedeutet, dass diese Destrukturierung äquivalent ist zu

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

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

x  0
y  0

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

x = 0
y = 0

Beispiel 2: move1({z:3})

[{x=0, y=0} = {}]  [{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 keine Eigenschaften x und y auf der rechten Seite und die Standardwerte werden verwendet

x = 0
y = 0
10.11.2.4 Schlussfolgerung

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

Weiter: 11. Parameterbehandlung