- для функций: где ожидаемое количество аргументов для вызовов функций равно нулю или больше нуля
- для элементов (литералов массива)
- для выражений объектов: в местах, где количество пар "ключ-значение" должно быть равно нулю или больше (для объектных литералов)
The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
Синтаксис
Для вызовов функций:
myFunction(...iterableObj);
Для литералов массива или строк:
[...iterableObj, '4', 'five', 6];
Для литералов объекта (новое в ECMAScript 2018):
let objClone = { ...obj };
Примеры
Spread в вызовах функций
Замена apply
Обычно используют Function.prototype.apply в случаях, когда хотят использовать элементы массива в качестве аргументов функции.
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
С spread syntax вышеприведенное можно записать как:
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);
Любой аргумент в списке аргументов может использовать spread syntax, и его можно использовать несколько раз.
function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
Apply для new
Вызывая конструктор через ключевое слово new, невозможно использовать массив и apply напрямую (apply выполняет [[Call]], а не [[Construct]]).Однако благодаря spread syntax, массив может быть с легкостью использован со словом new:
var dateFields = [1970, 0, 1]; // 1 Jan 1970 var d = new Date(...dateFields);
Чтобы использовать new с массивом параметров без spread syntax, вам потребуется использование частичного применения:
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 syntax, применение синтаксиса литерала массива для создания нового массива на основе существующего недостаточно и требуется императивный код вместо комбинации методов push, splice, concat и т.д. С spread syntax реализация становится гораздо более лаконичной:
var parts = ['shoulders', 'knees']; var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"]
Аналогично развертыванию в массиве аргументов, ... может быть использован повсеместно и многократно в литерале массива.
Копирование массива
var arr = [1, 2, 3]; var arr2 = [...arr]; // like arr.slice() arr2.push(4); // arr2 becomes [1, 2, 3, 4] // arr remains unaffected
Примечание: Spread syntax на самом деле переходит лишь на один уровень глубже при копировании массива. Таким образом, он может не подходить для копирования многоразмерных массивов, как показывает следующий пример: (также как и Object.assign())
var a = [[1], [2], [3]]; var b = [...a]; b.shift().shift(); // 1 // Now array a is affected as well: [[], [2], [3]]
Лучший способ конкатенации массивов
Для конкатенации массива часто используется Array.concat:
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; // Append all items from arr2 onto arr1 arr1 = arr1.concat(arr2);
С использованием spread syntax:
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1 = [...arr1, ...arr2];
Array.unshift часто используется для вставки массива значений в начало существующего массива. Без spread syntax:
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]
С использованием spread syntax [Следует отметить, что такой способ создает новый массив arr1. В отличие от Array.unshift, исходный массив не мутируется]:
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1 = [...arr2, ...arr1]; // arr1 is now [3, 4, 5, 0, 1, 2]
Spread в литералах объекта
Предложение Rest/Spread Properties for ECMAScript (стадия 4) добавляет свойства spread в литералы объекта. Оно копирует собственные перечисляемые свойства данного объекта в новый объект.
Поверхностное копирование (без прототипа) или объединение объектов теперь возможно с использованием более короткого, чем 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 }
Обратите внимание, что Object.assign() запускает setters, а spread syntax нет.
Обратите внимание, что вы не можете заменить или имитировать функцию Object.assign():
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 } }
В приведенном выше примере оператор распространения не работает так, как можно было бы ожидать: он распространяет массив аргументов в литерал объекта благодаря параметру rest.
Только для итерируемых объектов
Spread syntax ( кроме случаев spread properties) может быть применен только к итерируемым объектам (iterable objects) :
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
Spread с большим количеством значений
При использовании spread оператора в вызовах функций необходимо быть внимательным к возможному переполнению в ядре JavaScript. Существует ограничение по максимально возможному количеству аргументов функции. См. apply() для уточнения.
Rest синтаксис (параметры)
Синтаксис для rest оператора выглядит таким же как и для spread оператора, однако он используется для деструктуризации массивов и объектов. Фактически, rest оператор противоположен spread оператору: последний раскладывает массив на элементы, тогда как первый собирает много элементов в один. См. rest parameters.
Specifications
| Specification | Status | Comment |
|---|---|---|
| ECMAScript 2015 (6th Edition, ECMA-262) | Стандарт | Defined in several sections of the specification: Array Initializer, Argument Lists |
| ECMAScript 2018 (ECMA-262) | Стандарт | Defined in Object Initializer |
| ECMAScript Latest Draft (ECMA-262) | Черновик | No changes. |
| ECMAScript Latest Draft (ECMA-262) | Черновик | No changes. |
Browser compatibility
| Компьютеры | Мобильные | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Spread in array literals | Chrome Полная поддержка 46 | Edge Полная поддержка 12 | Firefox Полная поддержка 16 | IE Нет поддержки Нет | Opera Полная поддержка 37 | Safari Полная поддержка 8 | WebView Android Полная поддержка 46 | Chrome Android Полная поддержка 46 | Firefox Android Полная поддержка 16 | Opera Android Полная поддержка 37 | Safari iOS Полная поддержка 8 | Samsung Internet Android Полная поддержка 5.0 | nodejs
Полная поддержка
5.0.0
|
| Spread in function calls | Chrome Полная поддержка 46 | Edge Полная поддержка 12 | Firefox Полная поддержка 27 | IE Нет поддержки Нет | Opera Полная поддержка 37 | Safari Полная поддержка 8 | WebView Android Полная поддержка 46 | Chrome Android Полная поддержка 46 | Firefox Android Полная поддержка 27 | Opera Android Полная поддержка 37 | Safari iOS Полная поддержка 8 | Samsung Internet Android Полная поддержка 5.0 | nodejs
Полная поддержка
5.0.0
|
| Spread in destructuring | Chrome Полная поддержка 49 | Edge Нет поддержки Нет | Firefox Полная поддержка 34 | IE Нет поддержки Нет | Opera Полная поддержка 37 | Safari ? | WebView Android Полная поддержка 49 | Chrome Android Полная поддержка 49 | Firefox Android Полная поддержка 34 | Opera Android Полная поддержка 37 | Safari iOS ? | Samsung Internet Android Полная поддержка 5.0 | nodejs Полная поддержка Да |
| Spread in object literals | Chrome Полная поддержка 60 | Edge Нет поддержки Нет | Firefox Полная поддержка 55 | IE Нет поддержки Нет | Opera Полная поддержка 47 | Safari Полная поддержка 11.1 | WebView Android Полная поддержка 60 | Chrome Android Полная поддержка 60 | Firefox Android Полная поддержка 55 | Opera Android ? | Safari iOS Полная поддержка 11.1 | Samsung Internet Android Полная поддержка 8.2 | nodejs
Полная поддержка
8.3.0
|
Легенда
- Полная поддержка
- Полная поддержка
- Нет поддержки
- Нет поддержки
- Совместимость неизвестна
- Совместимость неизвестна
- Экспериментальная. Ожидаемое поведение может измениться в будущем.
- Экспериментальная. Ожидаемое поведение может измениться в будущем.
- Пользователь должен сам включить эту возможность.
- Пользователь должен сам включить эту возможность.
See also
- Rest parameters (also ‘
...’) - fn.apply (also ‘
...’)