Читать книгу JavaScript – Das Handbuch für die Praxis - David Flanagan - Страница 68
3.10.3Destrukturierende Zuweisung
ОглавлениеIn ES6 wurde eine Art zusammengesetzte Deklarations- und Zuweisungssyntax eingeführt, die als destrukturierende Zuweisung bezeichnet wird. Bei einer solchen destrukturierenden Zuweisung steht als Wert auf der rechten Seite des Gleichheitszeichens ein Array oder ein Objekt (ein »strukturierter« Wert), während auf der linken Seite einer oder mehrere Variablennamen in einer Syntax angegeben werden, die der von Array- und Objektliteralen ähnelt. Wenn eine destrukturierende Zuweisung erfolgt, wird einer oder werden mehrere Werte aus dem rechtsseitig angegebenen Wert extrahiert (»destrukturiert«) und in den links genannten Variablen gespeichert. Eine destrukturierende Zuweisung wird vermutlich am häufigsten verwendet, um Variablen als Teil einer const-, let- oder var-Deklarationsanweisung zu initialisieren, aber sie kann auch in regulären Zuweisungsausdrücken (mit bereits deklarierten Variablen) vorgenommen werden. Und wie wir in 8.3.5 sehen werden, kann man die Destrukturierung ebenfalls bei der Definition der Parameter einer Funktion einsetzen.
Hier einige einfache destrukturierende Zuweisungen mithilfe von Arrays von Werten:
let [x,y] = [1,2]; // Das Gleiche wie let x = 1, y = 2.
[x,y] = [x+1,y+1]; // Das Gleiche wie x = x + 1, y = y + 1.
[x,y] = [y,x]; // Die Werte der beiden Variablen werden vertauscht.
[x,y] // => [3,2]: Die inkrementierten und vertauschten Werte.
Destrukturierende Zuweisungen erleichtern insbesondere die Arbeit mit Funktionen, die Arrays von Werten zurückgeben:
// Umrechnung von [x,y]-Koordinaten in [r,theta]-Polarkoordinaten.
function toPolar(x, y) {
return [Math.sqrt(x*x+y*y), Math.atan2(y,x)];
}
// Umwandlung von polaren in kartesische Koordinaten.
function toCartesian(r, theta) {
return [r*Math.cos(theta), r*Math.sin(theta)];
}
let [r,theta] = toPolar(1.0, 1.0); // r == Math.sqrt(2); theta == Math.PI/4
let [x,y] = toCartesian(r,theta); // [x, y] == [1.0, 1,0]
Wir haben gesehen, dass Variablen und Konstanten als Teil der verschiedenen for-Schleifen von JavaScript deklariert werden können. Auch in diesem Kontext lässt sich die destrukturierende Zuweisung verwenden. Es folgt ein Codebeispiel, in dem die Name/Wert-Paare aller Eigenschaften eines Objekts in einer Schleife durchlaufen und diese Paare mithilfe einer destrukturierenden Zuweisung aus Arrays mit zwei Elementen in einzelne Variablen umgewandelt werden:
let o = { x: 1, y: 2 }; // Das Objekt, das per Schleife "durchlaufen" wird.
for(const [name, value] of Object.entries(o)) {
console.log(name, value); // Gibt "x 1" und "y 2" aus.
}
Die Anzahl der Variablen auf der linken Seite einer destrukturierenden Zuweisung muss nicht mit der Anzahl der Array-Elemente auf der rechten Seite übereinstimmen. Zusätzliche Variablen auf der linken Seite werden auf undefined gesetzt, und zusätzliche Werte auf der rechten Seite werden schlicht ignoriert. Die Liste der Variablen auf der linken Seite kann zusätzliche Kommata enthalten, um bestimmte Werte auf der rechten Seite zu überspringen:
let [x,y] = [1]; // x == 1; y == undefined
[x,y] = [1,2,3]; // x == 1; y == 2
[,x,,y] = [1,2,3,4]; // x == 2; y == 4
Wenn Sie beim Destrukturieren eines Arrays alle unbenutzten oder verbleibenden Werte in einer einzigen Variablen sammeln möchten, verwenden Sie drei Punkte (…) vor dem letzten Variablennamen auf der linken Seite:
let [x, …y] = [1,2,3,4]; // y == [2,3,4]
Wir werden diesen drei Punkten in 8.3.2 wiederbegegnen.
Die destrukturierende Zuweisung kann auch in verschachtelten Arrays verwendet werden. In diesem Fall sollte die linke Seite der Zuordnung wie ein verschachteltes Array-Literal aussehen:
let [a, [b, c]] = [1, [2,2.5], 3]; // a == 1; b == 2; c == 2.5
Es ist ein mächtiges Merkmal der Array-Destrukturierung, dass sie tatsächlich kein Array erfordert! Sie können jedes iterierbare Objekt (siehe Kapitel 12) auf der rechten Seite der Zuweisung verwenden; alle Objekte, die mit einer for/of-Schleife (siehe 5.4.4) genutzt werden können, können auch destrukturiert werden:
let [first, …rest] = "Hello"; // first == "H"; rest == ["e","l","l","o"]
Destrukturierende Zuweisungen können ebenfalls durchgeführt werden, wenn die rechte Seite ein Objektwert ist. In diesem Fall sieht die linke Seite der Zuweisung in etwa wie ein Objektliteral aus: eine durch Kommata getrennte Liste von Variablennamen innerhalb geschweifter Klammern:
let transparent = {r: 0.0, g: 0.0, b: 0.0, a: 1.0}; // Eine RGBA-Farbe.
let {r, g, b} = transparent; // r == 0.0; g == 0.0; b == 0.0
Im folgenden Beispiel werden globale Funktionen des Math-Objekts in Variablen kopiert, wodurch sich trigonometrielastiger Code vereinfachen ließe:
// Das Gleiche wie const sin=Math.sin, cos=Math.cos, tan=Math.tan.
const {sin, cos, tan} = Math;
Das Math-Objekt besitzt übrigens viele weitere Eigenschaften als nur die drei, die hier in einzelne Variablen destrukturiert werden. Hier nicht aufgeführte Eigenschaften werden einfach ignoriert. Enthielte die linke Seite dieser Zuweisung eine Variable, deren Name keiner Eigenschaft von Math entspricht, würde dieser Variablen einfach undefined zugewiesen werden.
In jedem dieser Beispiele für die Destrukturierung von Objekten haben wir Variablennamen gewählt, die mit den Eigenschaftsnamen des zu destrukturierenden Objekts übereinstimmen. Dadurch bleibt die Syntax einfach und leicht verständlich, es ist aber keine verpflichtende Vorgehensweise. Auf der linken Seite einer objektdestrukturierenden Zuweisung kann man auch Identifier-Paare verwenden, die durch einen Doppelpunkt getrennt sind, wobei der erste Identifier der Name der Eigenschaft ist, deren Wert zugewiesen werden soll, und der zweite Identifier der Name der Variablen, der er zugewiesen werden soll:
// Das Gleiche wie const cosine = Math.cos, tangent = Math.tan;
const { cos: cosine, tan: tangent } = Math;
Wenn die Variablen- und Eigenschaftsnamen nicht identisch sind, wird mir persönlich die Syntax der Objektdestrukturierung zu kompliziert, um wirklich nützlich zu sein, und ich neige dazu, in diesem Fall die Kurzschriftsyntax zu vermeiden. Wenn Sie sie verwenden möchten, denken Sie daran, dass Eigenschaftsnamen immer links vom Doppelpunkt stehen, sowohl in Objektliteralen als auch links von einer objektdestrukturierenden Zuweisung.
Noch komplizierter wird die destrukturierende Zuweisung, wenn sie bei verschachtelten Objekten oder Arrays von Objekten oder Objekten von Arrays zum Einsatz kommt, aber sie ist dort erlaubt:
let points = [{x: 1, y: 2}, {x: 3, y: 4}]; // Ein Array von zwei Punktobjekten.
let [{x: x1, y: y1}, {x: x2, y: y2}] = points; // Destrukturiert in 4 Variablen.
(x1 === 1 && y1 === 2 && x2 === 3 && y2 === 4) // => true
Anstelle eines Arrays von Objekten könnten wir auch ein Objekt aus Arrays destrukturieren:
let points = { p1: [1,2], p2: [3,4] }; // Ein Objekt mit 2 Arrays als
// Eigenschaften.
let { p1: [x1, y1], p2: [x2, y2] } = points; // Destrukturiert in 4 Variablen.
(x1 === 1 && y1 === 2 && x2 === 3 && y2 === 4) // => true
Komplexe Destrukturierungssyntax lässt sich oft schwer schreiben und lesen, und möglicherweise fahren Sie besser damit, wenn Sie Ihre Zuweisungen explizit mit traditionellem Code wie let x1 = points.p1[0]; formulieren.