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
245
246
247
248
249
250
251
252
253
|
---
title: Оператор розкладу
slug: Web/JavaScript/Reference/Operators/Spread_syntax
tags:
- ECMAScript 2015
- JavaScript
- Довідка
translation_of: Web/JavaScript/Reference/Operators/Spread_syntax
---
<div>{{jsSidebar("Operators")}}</div>
<p><strong>Оператор розкладу</strong> дозволяє розкласти ітерабельний об'єкт, такий як масив чи рядок, там, де очікується нуль чи більше аргументів (для викликів функцій) чи елементів (для масивних літералів), або розкласти об'єкт там, де очікується нуль або більше пар ключ-значення (для об'єктних літералів).</p>
<div>{{EmbedInteractiveExample("pages/js/expressions-spreadsyntax.html")}}</div>
<h2 id="Синтаксис">Синтаксис</h2>
<p>Для викликів функцій:</p>
<pre class="syntaxbox notranslate">myFunction(...iterableObj);
</pre>
<p>Для масивних літералів або рядків:</p>
<pre class="syntaxbox notranslate">[...iterableObj, "4", "п'ять", 6];</pre>
<p>Для об'єктних літералів (нове у ECMAScript 2018):</p>
<pre class="syntaxbox notranslate">let objClone = { ...obj };</pre>
<h2 id="Залишковий_синтаксис_параметри">Залишковий синтаксис (параметри)</h2>
<p>Залишковий синтаксис виглядає так само, як синтаксис розкладання, але використовується для <em>деструктуризації</em> масивів та об'єктів.</p>
<p>В певному сенсі, залишковий синтаксис є протилежністю синтаксису розкладу. Розклад "розпаковує" масив на його окремі елементи, в той час, як залишковий синтаксис збирає множину елементів та "стискає" їх у єдиний елемент. Дивіться {{jsxref("Functions/решта_параметрів", "залишкові параметри", "", 1)}}.</p>
<h2 id="Приклади">Приклади</h2>
<h3 id="Розклад_у_викликах_функцій"><a id="Spread_in_function_calls" name="Spread_in_function_calls">Розклад у викликах функцій</a></h3>
<h4 id="Заміна_apply">Заміна <code>apply()</code></h4>
<p>Зазвичай, {{jsxref("Function.prototype.apply()")}} використовується, коли ви бажаєте використати елементи масиву як аргументи у функції.</p>
<pre class="brush: js notranslate">function myFunction(x, y, z) { }
const args = [0, 1, 2];
myFunction.apply(null, args);</pre>
<p>З оператором розкладу наведене можна записати так:</p>
<pre class="brush: js notranslate">function myFunction(x, y, z) { }
const args = [0, 1, 2];
myFunction(...args);</pre>
<p>Будь-який аргумент у списку може використати синтаксис розкладу, і він може використовуватись неодноразово.</p>
<pre class="brush: js notranslate">function myFunction(v, w, x, y, z) { }
const args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);</pre>
<h4 id="Apply_для_оператора_new">Apply для оператора <code>new</code></h4>
<p>Викликаючи конструктор з {{jsxref("Operators/new", "new")}}, неможливо <strong>прямо</strong> використовувати масив та <code>apply</code> (<code>apply</code> виконує <code>[[Call]]</code>, а не <code>[[Construct]]</code>). Однак, масив можна легко використовувати з <code>new</code> завдяки синтаксису розкладу:</p>
<pre class="brush: js notranslate">const dateFields = [1970, 0, 1]; // 1 Січня 1970
const d = new Date(...dateFields);
</pre>
<p>Щоб використати new з масивом параметрів без розкладу, вам довелося б зробити це <strong>опосередковано</strong>, частковим застосуванням:</p>
<pre class="brush: js notranslate">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="знач1";
this.prop2="знач2";
};
var myArguments = ["вітаю", "як", "ся", "маєте", "п.", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);
console.log(new myConstructorWithArguments);
// (internal log of myConstructor): arguments.length: 6
// (internal log of myConstructor): ["вітаю", "як", "ся", "маєте", "п.", null]
// (log of "new myConstructorWithArguments"): {prop1: "знач1", prop2: "знач2"}</pre>
<h3 id="Розклад_у_масивних_літералах"><a id="Spread_in_array_literals" name="Spread_in_array_literals">Розклад у масивних літералах</a></h3>
<h4 id="Потужніший_масивний_літерал">Потужніший масивний літерал</h4>
<p>Без оператора розкладу, щоб створити новий масив, частиною якого є існуючий масив, літерального синтаксису масивів недостатньо, доводиться використовувати імперативний код з використанням комбінації з {{jsxref("Array.prototype.push", "push()")}}, {{jsxref("Array.prototype.splice", "splice()")}}, {{jsxref("Array.prototype.concat", "concat()")}}, і т. д. З синтаксисом розкладу все стає набагато лаконічнішим:</p>
<pre class="brush: js notranslate">var parts = ['плечі', 'коліна'];
var lyrics = ['голова', ...parts, 'та', 'пальці'];
// ["голова", "плечі", "коліна", "та", "пальці"]
</pre>
<p>Як і розклад аргументів, <code>...</code> може використовуватись будь-де у масивному літералі, і може використовуватись неодноразово.</p>
<h4 id="Копія_масиву">Копія масиву</h4>
<pre class="brush: js notranslate">const arr = [1, 2, 3];
const arr2 = [...arr]; // як arr.slice()
arr2.push(4);
// arr2 стає [1, 2, 3, 4]
// arr залишається незміненим
</pre>
<div class="blockIndicator note">
<p><strong>Заувага:</strong> Оператор розкладу ефективно йде на один рівень вглиб при копіюванні масиву. Тому він може бути непридатний для копіювання багатовимірних масивів, як показано у наступному прикладі (те саме з {{jsxref("Object.assign()")}} та розкладом).</p>
<pre class="brush: js example-bad notranslate">const a = [[1], [2], [3]];
const b = [...a];
b.shift().shift();
// 1
// О, ні! Тепер масив 'a' також змінився:
a
// [[], [2], [3]]</pre>
</div>
<h4 id="Краще_обєднання_масивів">Краще об'єднання масивів</h4>
<p>Метод {{jsxref("Array.prototype.concat()")}} часто використовується для приєднання масиву в кінець існуючого масиву. Без оператора розкладу це робиться так:</p>
<pre class="brush: js notranslate">const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
// Додати всі елементи з arr2 у arr1
arr1 = arr1.concat(arr2);</pre>
<p>З оператором розкладу отримуємо:</p>
<pre class="brush: js notranslate">let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
// arr1 тепер [0, 1, 2, 3, 4, 5]
// Заувага: Не використовуйте const, це спричинить TypeError (недозволене присвоєння)
</pre>
<p>Метод {{jsxref("Array.prototype.unshift()")}} часто використовується для додавання масиву значень у початок існуючого масиву. Без оператора розкладу це робиться так:</p>
<pre class="brush: js notranslate">const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
// Подати усі елементи з arr2 до arr1
Array.prototype.unshift.apply(arr1, arr2)
// arr1 тепер [3, 4, 5, 0, 1, 2]</pre>
<p>З оператором розкладу отримуємо:</p>
<pre class="brush: js notranslate">let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1];
// arr1 тепер [3, 4, 5, 0, 1, 2]
</pre>
<div class="blockIndicator note">
<p><strong>Заувага</strong>: На відміну від <code>unshift()</code>, цей код створює новий <code>arr1</code>, а не змінює початковий масив <code>arr1</code>.</p>
</div>
<h3 id="Розклад_у_обєктних_літералах"><a id="Spread_in_object_literals" name="Spread_in_object_literals">Розклад у об'єктних літералах</a></h3>
<p>Пропозиція <a href="https://github.com/tc39/proposal-object-rest-spread">Rest/Spread Properties for ECMAScript</a> (стадія 4) додала розкладені властивості до {{jsxref("Operators/Ініціалізація_об’єктів", "об'єктних літералів", 1)}}. Цей синтаксис копіює особисті, перелічувані властивості наданого об'єкта у новий об'єкт.</p>
<p>Дрібне клонування (без прототипу) чи злиття об'єктів тепер можливе за допомогою синтаксису, коротшого, ніж {{jsxref("Object.assign()")}}.</p>
<pre class="brush: js notranslate">const obj1 = { foo: 'bar', x: 42 };
const obj2 = { foo: 'baz', y: 13 };
const clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
const mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }</pre>
<p>Зауважте, що {{jsxref("Object.assign()")}} запускає {{jsxref("Functions/set", "сетери")}}, а оператор розкладу ні.</p>
<p>Зауважте, що ви не можете ані замінити, ані імітувати функцію {{jsxref("Object.assign()")}}:</p>
<pre class="brush: js notranslate">let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );
let mergedObj = merge ( obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }
let mergedObj = merge ( {}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }</pre>
<p>У наведеному прикладі оператор розкладу працює не так, як можна було очікувати: він розкладає <em>масив</em> аргументів у об'єктний літерал, через наявність залишкового параметра.</p>
<h3 id="Тільки_для_ітерабельних_обєктів">Тільки для ітерабельних об'єктів</h3>
<p>Самі по собі об'єкти не є ітерабельними, але вони стають ітерабельними, коли використовуються у масиві, або з функціями перебору, такими як <code>map()</code>, <code>reduce()</code> та <code>assign()</code>. При з'єднанні 2-х об'єктів за допомогою оператору розкладу, вважається, що застосовується функція перебору, коли відбувається з'єднання.</p>
<p>Оператор розкладу (окрім випадку розкладених властивостей) може застосовуватись тільки до <a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator">ітерабельних</a> об'єктів:</p>
<pre class="brush: js notranslate">const obj = {'key1': 'value1'};
const array = [...obj]; // TypeError: obj is not iterable
</pre>
<h3 id="Розклад_з_великою_кількістю_значень">Розклад з великою кількістю значень</h3>
<p>При використанні оператора розкладу для викликів функцій пам'ятайте про можливість перевищити ліміт кількості аргументів рушія JavaScript. Більше інформації дивіться у статті {{jsxref("Function.prototype.apply", "apply()")}}.</p>
<h2 id="Специфікації">Специфікації</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Специфікація</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ESDraft', '#sec-array-initializer', 'Array initializer')}}</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-object-initializer', 'Object initializer')}}</td>
</tr>
</tbody>
</table>
<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>
<p>{{Compat("javascript.operators.spread")}}</p>
<h2 id="Див._також">Див. також</h2>
<ul>
<li><a href="/uk/docs/Web/JavaScript/Reference/Functions/решта_параметрів">Залишкові параметри</a> (також ‘<code>...</code>’)</li>
<li><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">fn.apply</a> (також ‘<code>...</code>’)</li>
</ul>
|