undefined löst Standardwerte aus...)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).
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
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');
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
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'
Die folgenden beiden Parteien sind an der Destrukturierung beteiligt
Das Destrukturierungsziel ist eines von drei Mustern
x{ first: «muster», last: «muster» }[ «muster», «muster» ]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
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';
Bei einer Zuweisung muster = someValue, wie greift muster auf das Innere von someValue zu?
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
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).
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.
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
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
undefined (andernfalls)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
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.
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.
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
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 = {}] = [];
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
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
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
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'
...) 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']
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.
Es gibt zwei Dinge, die Sie bei der Verwendung von Destrukturierung beachten sollten
Die nächsten beiden Abschnitte enthalten die Details.
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
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']
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);
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);
}
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'
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.
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 }) { ··· }
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
{key: «muster», «properties»} ← obj «pattern» ← obj.key
{«properties»} ← obj
{} ← obj (keine Eigenschaften mehr übrig) // 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. 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.
Ein Muster ist entweder
x{«properties»}[«elements»]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.
x ← value (einschließlich undefined und null) x = value
{«properties»} ← undefined throw new TypeError();
{«properties»} ← null throw new TypeError();
{key: «muster», «properties»} ← obj «pattern» ← obj.key
{«properties»} ← obj
{key: «muster» = standardwert, «properties»} ← obj const tmp = obj.key;
if (tmp !== undefined) {
«pattern» ← tmp
} else {
«pattern» ← default_value
}
{«properties»} ← obj
{} ← obj (keine Eigenschaften mehr übrig) // Nothing to do
Array-Muster und Iterable. Der Algorithmus für die Array-Destrukturierung beginnt mit einem Array-Muster und einem Iterable
[«elements»] ← non_iterableassert(!isIterable(non_iterable))
throw new TypeError();
[«elements»] ← iterableassert(isIterable(iterable))
const iterator = iterable[Symbol.iterator]();
«elements» ← iterator
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.
«muster», «elements» ← iterator «pattern» ← getNext(iterator) // undefined after last item
«elements» ← iterator
«muster» = standardwert, «elements» ← iterator const tmp = getNext(iterator); // undefined after last item
if (tmp !== undefined) {
«pattern» ← tmp
} else {
«pattern» ← default_value
}
«elements» ← iterator
, «elements» ← iterator (Loch, Elision) getNext(iterator); // skip
«elements» ← iterator
...«muster» ← iterator (immer der letzte Teil!) const tmp = [];
for (const elem of iterator) {
tmp.push(elem);
}
«pattern» ← tmp
← iterator (keine Elemente mehr übrig) // Nothing to do
Hilfsfunktion
function getNext(iterator) {
const {done,value} = iterator.next();
return (done ? undefined : value);
}
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
x und y wegzulassen.move1() ohne Parameter aufzurufen (wie in der letzten Zeile).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.
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]
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.
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
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.