diff options
Diffstat (limited to 'files/ru/web/javascript/reference/operators/spread_syntax/index.html')
-rw-r--r-- | files/ru/web/javascript/reference/operators/spread_syntax/index.html | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/files/ru/web/javascript/reference/operators/spread_syntax/index.html b/files/ru/web/javascript/reference/operators/spread_syntax/index.html new file mode 100644 index 0000000000..c96be61337 --- /dev/null +++ b/files/ru/web/javascript/reference/operators/spread_syntax/index.html @@ -0,0 +1,249 @@ +--- +title: Spread syntax +slug: Web/JavaScript/Reference/Operators/Spread_syntax +translation_of: Web/JavaScript/Reference/Operators/Spread_syntax +--- +<div>{{jsSidebar("Operators")}}</div> + +<div><strong>Spread syntax</strong> позволяет расширить доступные для итерации элементы (например, массивы или строки) в местах</div> + +<ul> + <li>для функций: где ожидаемое количество аргументов для вызовов функций равно нулю или больше нуля</li> + <li>для элементов (литералов массива)</li> + <li>для выражений объектов: в местах, где количество пар "ключ-значение" должно быть равно нулю или больше (для объектных литералов)</li> +</ul> + +<div>{{EmbedInteractiveExample("pages/js/expressions-spreadsyntax.html")}}</div> + +<p class="hidden">Источник для этого интерактивного примера находится в репозитории на GitHub. Если вы желаете внести свой вклад в этот проект, то, пожалуйста, склонируйте себе <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> и пришлите нам pull request.</p> + +<h2 id="Синтаксис">Синтаксис</h2> + +<p>Для вызовов функций:</p> + +<pre class="syntaxbox notranslate">myFunction(...iterableObj); +</pre> + +<p>Для литералов массива или строк:</p> + +<pre class="syntaxbox notranslate">[...iterableObj, '4', 'five', 6];</pre> + +<p>Для литералов объекта (новое в ECMAScript 2018):</p> + +<pre class="syntaxbox notranslate">let objClone = { ...obj };</pre> + +<h2 id="Примеры">Примеры</h2> + +<h3 id="Spread_в_вызовах_функций">Spread в вызовах функций</h3> + +<h4 id="Замена_apply">Замена apply</h4> + +<p>Обычно используют {{jsxref( "Function.prototype.apply")}} в случаях, когда хотят использовать элементы массива в качестве аргументов функции.</p> + +<pre class="brush: js notranslate">function myFunction(x, y, z) { } +var args = [0, 1, 2]; +myFunction.apply(null, args);</pre> + +<p>С <strong>spread syntax</strong> вышеприведенное можно записать как:</p> + +<pre class="brush: js notranslate">function myFunction(x, y, z) { } +var args = [0, 1, 2]; +myFunction(...args);</pre> + +<p>Любой аргумент в списке аргументов может использовать <strong>spread syntax</strong>, и его можно использовать несколько раз.</p> + +<pre class="brush: js notranslate">function myFunction(v, w, x, y, z) { } +var args = [0, 1]; +myFunction(-1, ...args, 2, ...[3]);</pre> + +<h4 id="Apply_для_new">Apply для new</h4> + +<p>Вызывая конструктор через ключевое слово <code>new</code>, невозможно использовать массив и <code>apply</code> <strong>напрямую </strong>(<code>apply</code> выполняет <code>[[Call]]</code>, а не <code>[[Construct]]</code>).Однако благодаря spread syntax, массив может быть с легкостью использован со словом <code>new:</code></p> + +<pre class="brush: js notranslate">var dateFields = [1970, 0, 1]; // 1 Jan 1970 +var d = new Date(...dateFields); +</pre> + +<p>Чтобы использовать <code>new</code> с массивом параметров без spread syntax, вам потребуется использование частичного применения:</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="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="Spread_в_литералах_массива">Spread в литералах массива</h3> + +<h4 id="Более_мощный_литерал_массива">Более мощный литерал массива</h4> + +<p>Без spread syntax, применение синтаксиса литерала массива для создания нового массива на основе существующего недостаточно и требуется императивный код вместо комбинации методов <code>push</code>, <code>splice</code>, <code>concat</code> и т.д. С spread syntax реализация становится гораздо более лаконичной:</p> + +<pre class="brush: js notranslate">var parts = ['shoulders', 'knees']; +var lyrics = ['head', ...parts, 'and', 'toes']; +// ["head", "shoulders", "knees", "and", "toes"] +</pre> + +<p>Аналогично развертыванию в массиве аргументов, <code>...</code> может быть использован повсеместно и многократно в литерале массива.</p> + +<h4 id="Копирование_массива">Копирование массива</h4> + +<pre class="brush: js notranslate">var arr = [1, 2, 3]; +var arr2 = [...arr]; // like arr.slice() +arr2.push(4); + +// arr2 becomes [1, 2, 3, 4] +// arr remains unaffected +</pre> + +<p><strong>Примечание:</strong> Spread syntax на самом деле переходит лишь на один уровень глубже при копировании массива. Таким образом, он может не подходить для копирования многоразмерных массивов, как показывает следующий пример: (также как и c {{jsxref("Object.assign()")}}) и синтаксис spred </p> + +<pre class="brush: js notranslate">const a = [[1], [2], [3]]; +const b = [...a]; +b.shift().shift(); // 1 +// О нет. Теперь на массив "а" относятся также: а +//[[], [2], [3]] +</pre> + +<h4 id="Лучший_способ_конкатенации_массивов">Лучший способ конкатенации массивов</h4> + +<p>Для конкатенации массива часто используется {{jsxref("Array.concat")}}:</p> + +<pre class="brush: js notranslate">var arr1 = [0, 1, 2]; +var arr2 = [3, 4, 5]; +// Append all items from arr2 onto arr1 +arr1 = arr1.concat(arr2);</pre> + +<p>С использованием spread syntax:</p> + +<pre class="brush: js notranslate">var arr1 = [0, 1, 2]; +var arr2 = [3, 4, 5]; +arr1 = [...arr1, ...arr2]; +</pre> + +<p>{{jsxref("Array.unshift")}} часто используется для вставки массива значений в начало существующего массива. Без spread syntax:</p> + +<pre class="brush: js notranslate">var arr1 = [0, 1, 2]; +var arr2 = [3, 4, 5]; +// Prepend all items from arr2 onto arr1 +Array.prototype.unshift.apply(arr1, arr2) // arr1 is now [3, 4, 5, 0, 1, 2]</pre> + +<p>С использованием spread syntax [Следует отметить, что такой способ создает новый массив <code>arr1</code>. В отличие от {{jsxref("Array.unshift")}}, исходный массив не мутируется]:</p> + +<pre class="brush: js notranslate">var arr1 = [0, 1, 2]; +var arr2 = [3, 4, 5]; +arr1 = [...arr2, ...arr1]; // arr1 is now [3, 4, 5, 0, 1, 2] +</pre> + +<h3 id="Spread_в_литералах_объекта">Spread в литералах объекта</h3> + +<p>Предложение <a href="https://github.com/tc39/proposal-object-rest-spread">Rest/Spread Properties for ECMAScript</a> (стадия 4) добавляет свойства spread в <a href="/ru/docs/Web/JavaScript/Reference/Operators/Object_initializer">литералы объекта</a>. Оно копирует собственные перечисляемые свойства данного объекта в новый объект.</p> + +<p>Поверхностное копирование (без прототипа) или объединение объектов теперь возможно с использованием более короткого, чем {{jsxref("Object.assign()")}}, синтаксиса.</p> + +<pre class="brush: js notranslate">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>Обратите внимание, что {{jsxref("Object.assign()")}} запускает <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setters</a>, а <strong>spread syntax</strong> нет.</p> + +<p>Обратите внимание, что вы не можете заменить или имитировать функцию {{jsxref("Object.assign()")}}:</p> + +<pre class="brush: js notranslate">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>В приведенном выше примере оператор распространения не работает так, как можно было бы ожидать: он распространяет <em>массив</em> аргументов в литерал <em>объекта</em> благодаря параметру rest.</p> + +<h3 id="Только_для_итерируемых_объектов">Только для итерируемых объектов</h3> + +<p>Spread syntax ( кроме случаев spread properties) может быть применен только к итерируемым объектам (<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator">iterable</a> objects) :</p> + +<pre class="brush: js notranslate">var obj = {'key1': 'value1'}; +var array = [...obj]; // TypeError: obj is not iterable +</pre> + +<h3 id="Spread_с_большим_количеством_значений">Spread с большим количеством значений</h3> + +<p>При использовании spread оператора в вызовах функций необходимо быть внимательным к возможному переполнению в ядре JavaScript. Существует ограничение по максимально возможному количеству аргументов функции. См. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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="Rest_синтаксис_параметры">Rest синтаксис (параметры)</h2> + +<p>Синтаксис для rest оператора выглядит таким же как и для spread оператора, однако он используется для деструктуризации массивов и объектов. Фактически, rest оператор противоположен spread оператору: последний раскладывает массив на элементы, тогда как первый собирает много элементов в один. См. <a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">rest parameters.</a></p> + +<h2 id="Specifications">Specifications</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>Без изменений.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-object-initializer')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td>Без изменений.</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility">Browser compatibility</h2> + + + +<p>{{Compat("javascript.operators.spread")}}</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters">Rest parameters</a> (also ‘<code>...</code>’)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">fn.apply</a> (also ‘<code>...</code>’)</li> +</ul> |