aboutsummaryrefslogtreecommitdiff
path: root/files/pl/web/javascript/reference/operators/spread_syntax/index.html
blob: a45d730722ec3a302470eb04bf938af2f582c325 (plain)
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
237
238
239
240
241
242
243
244
---
title: Składnia rozwinięcia
slug: Web/JavaScript/Referencje/Operatory/Składnia_rozwinięcia
translation_of: Web/JavaScript/Reference/Operators/Spread_syntax
---
<div>{{jsSidebar("Operators")}}</div>

<div><strong>Składnia rozwinięcia</strong> (ang. <em>spread syntax</em>) pozwala na rozwinięcie iterowalnego wyrażenia, takiego jak wyrażenie tablicowe lub ciąg znaków, tam gdzie oczekiwanych jest zero lub więcej argumentów (dla wywołań funkcji) lub elementów (dla literałów tablicowych). Pozwala również na rozwinięcie wyrażeń obiektowych w miejscach, gdzie oczekiwanych jest zero lub więcej par klucz-wartość (dla literałów obiektowych).</div>

<div> </div>

<div>{{EmbedInteractiveExample("pages/js/expressions-spreadsyntax.html")}}</div>



<h2 id="Składnia">Składnia</h2>

<p>Dla wywołań funkcji:</p>

<pre class="syntaxbox">mojaFunkcja(...iterowalnyObiekt);
</pre>

<p>Dla literałów tablicowych lub łańcuchów znaków:</p>

<pre class="syntaxbox">[...iterowalnyObiekt, '3', 'cztery', 5];</pre>

<p>Dla literałów obiektowych (nowe w ECMAScript 2018):</p>

<pre class="syntaxbox">let klonObiektu = { ...obiekt };</pre>

<h2 id="Przykłady">Przykłady</h2>

<h3 id="Rozwinięcie_w_wywołaniach_funkcji">Rozwinięcie w wywołaniach funkcji</h3>

<h4 id="Zastąpienie_apply">Zastąpienie <code>apply</code></h4>

<p>Powszechne jest używanie {{jsxref( "Function.prototype.apply")}} w przypadkach, w których chcemy użyć elementów tablicy jako argumentów funkcji.</p>

<pre class="brush: js">function mojaFunkcja(x, y, z) { }
var argumenty = [0, 1, 2];
mojaFunkcja.apply(null, argumenty);</pre>

<p>Przy użyciu operatora rozpakowania można to zapisać jako:</p>

<pre class="brush: js">function mojaFunkcja(x, y, z) { }
var argumenty = [0, 1, 2];
mojaFunkcja(...argumenty);</pre>

<p>Każdy argument na liście argumentów może użyć operatora rozpakowania, można go także używać wielokrotnie.</p>

<pre class="brush: js">function mojaFunkcja(v, w, x, y, z) { }
var argumenty = [0, 1];
mojaFunkcja(-1, ...argumenty, 2, ...[3]);</pre>

<h4 id="Apply_for_new">Apply for new</h4>

<p>When calling a constructor with <code>new</code>, it's not possible to <strong>directly</strong> use an array and <code>apply</code> (<code>apply</code> does a <code>[[Call]]</code> and not a <code>[[Construct]]</code>). However, an array can be easily used with <code>new</code> thanks to spread syntax:</p>

<pre class="brush: js">var dateFields = [1970, 0, 1];  // 1 Jan 1970
var d = new Date(...dateFields);
</pre>

<p>To use new with an array of parameters without spread syntax, you would have to do it <strong>indirectly</strong> through partial application:</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", "how", "are", "you", "mr", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);

console.log(new myConstructorWithArguments);
// (internal log of myConstructor):           arguments.length: 6
// (internal log of myConstructor):           ["hi", "how", "are", "you", "mr", null]
// (log of "new myConstructorWithArguments"): {prop1: "val1", prop2: "val2"}</pre>

<h3 id="Rozwinięcie_w_literałach_tablicowych">Rozwinięcie w literałach tablicowych</h3>

<h4 id="Potężniejszy_literał_tablicowy">Potężniejszy literał tablicowy</h4>

<p>Bez składni rozwinięcia, aby utworzyć nową tablicę, używając tablicy już istniejącej jako jej części, składnia literału tablicowego nie jest już wystarczająca i musimy użyć kodu imperatywnego, używając kombinacji <code>push</code>, <code>splice</code>, <code>concat</code> itd. Z użyciem składni rozwinięcia staje się to o wiele prostsze i bardziej zwięzłe:</p>

<pre class="brush: js">var czesci = ['kotek', 'na', 'plotek'];
var wierszyk = ['wlazl', ...czesci, 'i', 'mruga'];
// ["wlazl", "kotek", "na", "plotek", "i", "mruga"]
</pre>

<p>Tak jak dla list argumentów w wywołaniach funkcji, operator <code>...</code> może być użyty wielokrotnie i w każdym miejscu literału tablicowego.</p>

<h4 id="Kopia_tablicy">Kopia tablicy</h4>

<pre class="brush: js">var tab = [1, 2, 3];
var tab2 = [...tab]; // jak tab.slice()
tab2.push(4);

// tab2 staje się [1, 2, 3, 4]
// tab pozostaje niezmieniona
</pre>

<p><strong>Uwaga:</strong> Składnia rozwinięcia skutecznie sięga tylko na jeden poziom wgłąb przy kopiowaniu tablicy. W związku z tym takie podejście może być nieodpowiednie przy kopiowaniu tablic wielowymiarowych, jak pokazuje poniższy przykład (tak samo jest z {{jsxref("Object.assign()")}}  i kładnią rozwinięcia).</p>

<pre class="brush: js">var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// Tablica a została zmodyfikowana: [[], [2], [3]]
</pre>

<h4 id="Lepszy_sposób_na_łączenie_tablic">Lepszy sposób na łączenie tablic</h4>

<p>{{jsxref("Array.concat")}} jest często używane do dołączania elementów jednej tablicy na koniec drugiej. Bez składni rozwinięcia wygląda to tak:</p>

<pre class="brush: js">var tab1 = [0, 1, 2];
var tab2 = [3, 4, 5];
// Dołącz wszystkie elementy tab2 na koniec tab1
tab1 = tab1.concat(tab2);</pre>

<p>Przy użyciu składni rozwinięcia wygląda to natomiast tak:</p>

<pre class="brush: js">var tab1 = [0, 1, 2];
var tab2 = [3, 4, 5];
tab1 = [...tab1, ...tab2];
</pre>

<p>{{jsxref("Array.unshift")}} jest często używane do dołączania elementów jednej tablicy na początek drugiej. Bez składni rozwinięcia wygląda to w następujący sposób:</p>

<pre class="brush: js">var tab1 = [0, 1, 2];
var tab2 = [3, 4, 5];
// Dodaj wszystkie elementy tab2 na początek tab1
Array.prototype.unshift.apply(tab1, tab2) // tab1 staje się [3, 4, 5, 0, 1, 2]</pre>

<p>Przy użyciu składni rozwinięcia otrzymuje to następującą postać [jednak zauważ, że w tym przypadku utworzona zostaje nowa tablica <code>tab1</code> – w odróżnieniu od {{jsxref("Array.unshift")}}, <code>tab1</code> nie jest automatycznie modyfikowana):</p>

<pre class="brush: js">var tab1 = [0, 1, 2];
var tab2 = [3, 4, 5];
tab1 = [...tab2, ...tab1]; // tab1 staje się [3, 4, 5, 0, 1, 2]
</pre>

<h3 id="Rozwinięcie_w_literałach_tablicowych_2">Rozwinięcie w literałach tablicowych</h3>

<p>The <a href="https://github.com/tc39/proposal-object-rest-spread">Rest/Spread Properties for ECMAScript</a> proposal (stage 4) adds spread properties to <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">object literals</a>. It copies own enumerable properties from a provided object onto a new object.</p>

<p>Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than {{jsxref("Object.assign()")}}.</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>Note that {{jsxref("Object.assign()")}} triggers <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setters</a> whereas spread syntax doesn't.</p>

<p>Note that you cannot replace nor mimic the {{jsxref("Object.assign()")}} function:</p>

<pre class="brush: js">var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) =&gt; ( { ...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>In the above example, the spread syntax does not work as one might expect: it spreads an <em>array</em> of arguments into the object literal, due to the rest parameter.</p>

<h3 id="Tylko_dla_obiektów_iterowalnych">Tylko dla obiektów iterowalnych</h3>

<p>Składnia rozwinięcia może być użyta jedynie dla obiektów<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator"> iterowalnych</a>:</p>

<pre class="brush: js">var obiekt = {'klucz1': 'wartosc1'};
var tablica = [...obiekt]; // TypeError: obiekt is not iterable
</pre>

<h3 id="Rozwinięcie_z_wieloma_wartościami">Rozwinięcie z wieloma wartościami</h3>

<p>Kiedy używaż składni rozwinięcia do wywołań funkcji, musisz być świadomy możliwości przekroczenia limitu liczby argumentów w silniku JavaScript. Po więcej szczegółów zajrzyj do <a href="https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Function/apply" title="The apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object)."><code>apply()</code>.</a></p>

<h2 id="Składnia_reszty_(parametry)">Składnia reszty (parametry)</h2>

<p>Składnia reszty ang. <em>rest syntax</em>) wygląda dokładnie jak składnia rozwinięcia, ale jest używana do destrukturyzacji tablic i obiektów. W pewnym sensie składnia reszty jest przeciwieństwem składni rozpakowania: rozwinięcie „rozpakowuje” elementy tablicy, natomiast składnia reszty „zbiera” wiele elementów i „pakuje” je do pojedynczego elementu. Zobacz: <a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">rest parameters.</a></p>

<h2 id="Specyfikacje">Specyfikacje</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('ES2015', '#sec-array-initializer')}}</td>
   <td>{{Spec2('ES2015')}}</td>
   <td>Defined in several sections of the specification: <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('ES2018', '#sec-object-initializer')}}</td>
   <td>{{Spec2('ES2018')}}</td>
   <td>Defined in <a href="http://www.ecma-international.org/ecma-262/9.0/#sec-object-initializer">Object Initializer</a></td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-array-initializer')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td>No changes.</td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-object-initializer')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td>No changes.</td>
  </tr>
 </tbody>
</table>

<h2 id="Wsparcie_przeglądarek">Wsparcie przeglądarek</h2>



<p>{{Compat("javascript.operators.spread")}}</p>

<h2 id="Zobacz_też">Zobacz też</h2>

<ul>
 <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">Rest parameters</a> (również ‘<code>...</code>’)</li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">fn.apply</a> (również ‘<code>...</code>’)</li>
</ul>