MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-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-ей стадии.

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

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) Нет Нет Нет Нет

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

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

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