1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
---
title: Spread syntax
slug: Web/JavaScript/Reference/Operators/Spread_syntax
translation_of: Web/JavaScript/Reference/Operators/Spread_syntax
---
<div>{{jsSidebar("Operators")}}</div>
<div>Die <strong>Spread-Syntax </strong>erlaubt es, einen einzelnen Array-Ausdruck oder String an Stellen zu expandieren, an denen Null oder mehr Argumente (für Funktionsaufrufe) oder Elemente (für Array-Literale) erwartet werden, oder einen Objekt-Ausdruck an Stellen zu expandieren, an denen Null oder mehr Schlüssel-Wert-Paare (für Objektliterale) erwartet werden.</div>
<div>{{EmbedInteractiveExample("pages/js/expressions-spreadsyntax.html")}}</div>
<h2 id="Syntax">Syntax</h2>
<p>Für Funktionsaufrufe:</p>
<pre class="syntaxbox">myFunction(...iterableObj);
</pre>
<p>Für Array-Literale oder Strings:</p>
<pre class="syntaxbox">[...iterableObj, '4', 'fünf', 6];</pre>
<p>Für Objektliterale (neu in ECMAScript 2018):</p>
<pre class="syntaxbox">let objClone = { ...obj };</pre>
<h2 id="Beispiele">Beispiele</h2>
<h3 id="Spread_in_Funktionsaufrufen">Spread in Funktionsaufrufen</h3>
<h4 id="Apply_ersetzen">Apply ersetzen</h4>
<p>Es ist üblich {{jsxref( "Function.prototype.apply")}} zu benutzen, wenn man die Elemente eines Arrays als Argumente eines Funktionsaufrufs nutzen möchte.</p>
<pre class="brush: js">function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);</pre>
<p>Mit der Spread-Syntax lässt sich das ganze wie folgt schreiben:</p>
<pre class="brush: js">function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);</pre>
<p>Jedes Argument der Argumentliste kann die Spread-Syntax verwenden, und sie kann auch mehrfach verwendet werden.</p>
<pre class="brush: js">function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);</pre>
<h4 id="Apply_bei_new">Apply bei new</h4>
<p>Beim Aufruf eines Konstruktors mit <code>new</code>, ist es nicht möglich ein Array und <code>apply</code> <strong>direkt </strong>zu benutzen (<code>apply</code> führt <code>[[Call]]</code> und nicht <code>[[Construct]]</code> aus). Allerdings kann dank der Spread-Syntax ein Array mit <code>new</code> verwendet werden:</p>
<pre class="brush: js">var dateFields = [1970, 0, 1]; // 1. Januar 1970
var d = new Date(...dateFields);
</pre>
<p>Um <code>new</code> mit einem Array ohne die Spread-Syntax zu nutzen, müsste man das <strong>indirekt </strong>mit <em>Partial Application</em> umsetzen:</p>
<pre class="brush: js">function applyAndNew(constructor, args) {
function partial () {
return constructor.apply(this, args);
};
if (typeof constructor.prototype === "object") {
partial.prototype = Object.create(constructor.prototype);
}
return partial;
}
function myConstructor () {
console.log("arguments.length: " + arguments.length);
console.log(arguments);
this.prop1="val1";
this.prop2="val2";
};
var myArguments = ["hi", "wie", "geht's", "dir", "kumpel", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);
console.log(new myConstructorWithArguments);
// (internal log of myConstructor): arguments.length: 6
// (internal log of myConstructor): ["hi", "wie", "geht's", "dir", "kumpel", null]
// (log of "new myConstructorWithArguments"): {prop1: "val1", prop2: "val2"}</pre>
<h3 id="Spread_bei_Array-Literalen">Spread bei Array-Literalen</h3>
<h4 id="Ein_mächtigeres_Array-Literal">Ein mächtigeres Array-Literal</h4>
<p>Ohne Spread-Syntax ist die Array-Literal-Syntax nicht ausreichend, um ein neues Array zu erzeugen, das aus einem bereits existierenden Array besteht. Man muss dann auf imperative Programmierung mit einer Kombination aus <code>push</code>, <code>splice</code>, <code>concat</code>, etc. umsteigen. Mit Spread-Syntax wird der Code kurz und bündig:</p>
<pre class="brush: js">var parts = ['Schultern', 'Knie'];
var lyrics = ['Kopf', ...parts, 'und', 'Zehen'];
// ["Kopf", "Schultern", "Knie", "und", "Zehen"]
</pre>
<p>Genau wie bei Argumentlisten von Funktionsaufrufen kann <code>...</code> überall und mehrach bei Array-Literalen benutzt werden.</p>
<h4 id="Ein_Array_kopieren">Ein Array kopieren</h4>
<pre class="brush: js">var arr = [1, 2, 3];
var arr2 = [...arr]; // wie arr.slice()
arr2.push(4);
// arr2 enthält[1, 2, 3, 4]
// arr bleibt unverändert
</pre>
<p><strong>Bemerkung:</strong> Spread-Syntax geht beim Kopieren eines Arrays effektiv eine Ebene tief. Daher kann es für das Kopieren mehrdimensionaler Arrays ungeeignet sein, wie das folgende Beispiel zeigt (dasselbe gilt für {{jsxref("Object.assign()")}} und Spread-Syntax).</p>
<pre class="brush: js">var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// Auch Array a wurde verändert. [[], [2], [3]]
</pre>
<h4 id="Eine_bessere_Möglichkeit_Arrays_zu_verketten">Eine bessere Möglichkeit, Arrays zu verketten</h4>
<p>{{jsxref("Array.concat")}} wird oft verwendet, um ein Array an das Ende eines bestehenden Arrays anzuhängen. Ohne Spread-Syntax wird dies wie folgt gemacht:</p>
<pre class="brush: js">var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Hänge alle Elemente von arr2 an arr1
arr1 = arr1.concat(arr2);</pre>
<p>Mit Spread-Syntax wird daraus:</p>
<pre class="brush: js">var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
</pre>
<p>{{jsxref("Array.unshift")}} wird oft verwendet, um ein Array von Werten am Anfang eines bestehenden Arrays einzufügen. Ohne Spread-Syntax wird dies wie folgt gemacht:</p>
<pre class="brush: js">var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Alle Items von arr2 auf arr1 voranstellen
Array.prototype.unshift.apply(arr1, arr2) // arr1 ist jetzt [3, 4, 5, 0, 1, 2]</pre>
<p>Bei der Spread-Syntax wird dies zu [Beachten Sie jedoch, dass dies ein neues Array <code>arr1</code> erzeugt. Im Gegensatz zu {{jsxref("Array.unshift")}} ändert es nicht das ursprüngliche Array <code>arr1</code> in-place]:</p>
<pre class="brush: js">var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1]; // arr1 ist jetzt [3, 4, 5, 0, 1, 2]
</pre>
<h3 id="Spread_für_Objektliterale">Spread für Objektliterale</h3>
<p>Der Vorschlag zu <a href="https://github.com/tc39/proposal-object-rest-spread">Rest-/Spread-Attributen für ECMAScript</a> (Stufe 4) fügt Spread-Attribute zu <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">Objektliteralen</a> hinzu. Dadurch werden die abzählbaren Attribute von einem gegebenen Objekt zu einem neuen hinzugefügt.</p>
<p>Flaches Klonen (ohne <code>prototype</code>) oder Zusammenführen von Objekten ist nun mit einer kürzeren Syntax als {{jsxref("Object.assign()")}} möglich.</p>
<pre class="brush: js">var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }</pre>
<p>Beachten Sie, dass {{jsxref("Object.assign()")}}} im Gegensatz zur Spread-Syntax <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">Setter</a> auslöst.</p>
<p>Beachten Sie, dass Sie die Funktion {{jsxref("Object.assign()")}} weder ersetzen noch nachahmen können:</p>
<pre class="brush: js">var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );
var mergedObj = merge ( obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: "baz", y: 13 } }
var mergedObj = merge ( {}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: "baz", y: 13 } }</pre>
<p>Im obigen Beispiel funktioniert der Spread-Operator nicht wie erwartet: er klappt ein Array von Argumenten aus und liefert ein Array dieser, aufgrund des rest Parameters.</p>
<h3 id="Nur_für_iterierbare_Objekte">Nur für iterierbare Objekte</h3>
<p>Spread-Syntax (anders als bei Spread-Eigenschaften) kann nur auf <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator">iterierbare Objekte</a> angewendet werden:</p>
<pre class="brush: js">var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
</pre>
<h3 id="Spread_mit_mehreren_Werten">Spread mit mehreren Werten</h3>
<p>Beachten Sie bei der Verwendung von Spread-Syntax für Funktionsaufrufe die Möglichkeit der Überschreitung der Argumentlängenbegrenzung der JavaScript-Engine. Siehe <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply" title="Die Methode apply() ruft eine Funktion mit einem vorgegeben Wert für this auf sowie weiteren Argumenten, die als Array (oder Array-ähnliches Objekt) bereitgestellt werden."><code>apply()</code></a> für weitere Details.</p>
<h2 id="Rest-Syntax_(Parameter)">Rest-Syntax (Parameter)</h2>
<p>Rest-Syntax sieht genauso aus wie die Spread-Syntax und wird für das Destrukturieren von Arrays und Objekten eingesetzt. Rest-Syntax ist sozusagen das Gegenteil von Spread-Syntax: Spread klappt die einzelnen Bestandteile eines Arrays aus, während Rest verschiedene einzelne Elemente zu einem Array zusammenfasst. Siehe <a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">Rest-Parameter.</a></p>
<h2 id="Spezifikationen">Spezifikationen</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Spezifikation</th>
<th scope="col">Status</th>
<th scope="col">Kommentar</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ES2015', '#sec-array-initializer')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Definiert in mehreren Abschnitten der Spezifikation: <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-array-initializer">Array Initializer</a>, <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-argument-lists">Argument Lists</a></td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-array-initializer')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td>Keine Änderungen</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-object-initializer')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td>Definiert in <a href="https://tc39.github.io/ecma262/2018/#sec-object-initializer">Object Initializer</a></td>
</tr>
</tbody>
</table>
<h2 id="Browser-Kompatibilität">Browser-Kompatibilität</h2>
<p>{{Compat("javascript.operators.spread")}}</p>
<h2 id="Siehe_auch">Siehe auch</h2>
<ul>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">Rest-Parameters</a> (ebenfalls ‘<code>...</code>’)</li>
</ul>
|