MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-survey

Сводка

Оператор расширения позволяет расширять выражения в тех местах, где предусмотрено использование нескольких аргументов (при вызовах функции) или ожидается несколько элементов (для массивов).

Синтаксис

При вызовах функции:

f(...iterableObj);

В литералах массива:

[...iterableObj, 4, 5, 6]

При деструктурирующем присваивании:

[a, b, ...iterableObj] = [1, 2, 3, 4, 5];

Примеры

В вызовах функций

Замена для apply

В случаях, когда вы хотите использовать значения массива как аргументы при вызове функции, обычно используется Function.prototype.apply.

function f(x, y, z) { }
var args = [0, 1, 2];
f.apply(null, args);

При помощи spread пример выше можно переписать так:

function f(x, y, z) { }
var args = [0, 1, 2];
f(...args);

Оператор может использоваться для любого аргумента, в том числе и несколько раз:

function f(v, w, x, y, z) { }
var args = [0, 1];
f(-1, ...args, 2, ...[3]);

Использование с new

Используя apply нет возможности вызвать конструктор с использованием new с аргументами, представленными в виде массива (apply выполняет [[Call]], а не [[Construct]]). Однако используя spread вместо apply это сделать можно:

var dateFields = readDateFields(database);
var d = new Date(...dateFields);

Чтобы использовать new с массивом параметров вместо spread, необходимо использовать дополнительную прослойку:

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"}

Spread в литералах массивов

Более мощный литерал массива

Если вы хотите использовать существующий массив как часть нового без использования spread, то синтаксис литералов вам не поможет и придётся использовать императивный подход с комбинацией push, splice, concat и т.п. При помощи spread это можно сделать гораздо проще:

var parts = ['плечи', 'колени'];
var lyrics = ['голова', ...parts, 'и', 'пальцы'];
// ["голова", "плечи", "колени", "и", "пальцы"]

Также как и в случае со списком аргументов функции, ... может быть использован в любом месте определения массива, в том числе и многократно.

Копирование массива

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4); 

// теперь arr2 содержит [1, 2, 3, 4]
// arr остается неизменным

Заметьте: При копировании массивов spread, как и Object.assign() для литералов объектов, копирует только первый уровень массива. Следовательно, использование spread для копирования многомерных массивов является неподобающим. 

var a = [[1], [2], [3]];
var b = [...a]; // [[1], [2], [3]]
b.shift().shift(); // 1
// Массив a так же подвергся изменению: [[], [2], [3]]

Копирование массива

Array.concat часто используется для контенации массива в конец другого массива. Без использования spread это будет выглядеть так:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Вставить все значения из массива arr2 в конец arr1
arr1 = arr1.concat(arr2);
// arr1 теперь содержит [0, 1, 2, 3, 4, 5]

А с использованием spread:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];

Array.unshift часто используется для вставки массива в начало другого массива. Без использования spread это будет выглядеть так:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Вставить все значения массива из arr2 в начало arr1
Array.prototype.unshift.apply(arr1, arr2)

С использованием spread:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1];

Spread в литералах объектов

Предложение https://github.com/tc39/proposal-object-rest-spread (стадия 3) добавляет возможность использовать spread на литералах объектов. Spread копирует перечисляемые свойства объекта в другой объект.

Одноуровневое копирование (исключая свойство prototype) или слияние объектов станут доступны в более коротком синтаксисе, нежели при использовании Object.assign().

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 }

Обратите внимание на то, что spread не использует сеттеры, в отличие от Object.assign().

Только для итерируемых объектов

Spread может быть применен только к итерируемым объектам:

var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable

Rest (параметры)

Rest выглядит в точности, как и spread, но используется для деструктуризации массивов и объектов. В некотором смысле, rest является противоположностью spread: spread 'раскрывает' массив, в то время как rest собирает множество элементов внутрь одного массива. Параметры rest.

Спецификации

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262) Стандарт Определён в нескольких секциях спецификации: Инициализатор массивов, Списки аргументов
ECMAScript Latest Draft (ECMA-262) Черновик Без изменений.
Rest/Spread Properties for ECMAScript Draft Черновик на 3-ей стадии.

Совместимость с браузерами

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!

Feature Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Spread в литералах массивов 46 20 (12.10240) 16 (16) Нет 37 7.1
Spread в вызовах функций 46 20 (12.10240) 27 (27) Нет 37 7.1
Spread при деструктуризации 49 Нет 34 (34) Нет 37 ?
Spread в литералах объектов 60 Нет 55 (55) Нет Нет Нет
Feature Android Webview Edge Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Spread в литералах массивов 46 20 (12.10240) 16.0 (16) Нет Нет 8 46
Spread в вызовах функций 46 20 (12.10240) 27.0 (27) Нет Нет 8 46
Spread при деструктуризации Нет Нет 34.0 (34) ? ? ? Нет
Spread в литералах объектов Нет Нет 55.0 (55) Нет Нет Нет Нет

Смотрите также

Метки документа и участники

 Внесли вклад в эту страницу: dima74, pertu, redishko, kdex, midvik, nkapliev, standy, BychekRU, KrickRay, xowiun, dtretyakov
 Обновлялась последний раз: dima74,