Spread syntax
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.
Spread syntax позволяет расширить доступные для итерации элементы (например, массивы или строки) в местах
- для функций: где ожидаемое количество аргументов для вызовов функций равно нулю или больше нуля
- для элементов (литералов массива)
- для выражений объектов: в местах, где количество пар "ключ-значение" должно быть равно нулю или больше (для объектных литералов)
Интерактивный пример
Синтаксис
Для вызовов функций:
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 на самом деле переходит лишь на один уровень глубже при копировании массива. Таким образом, он может не подходить для копирования многоразмерных массивов, как показывает следующий пример: (также как и c Object.assign()
) и синтаксис spred
const a = [[1], [2], [3]];
const b = [...a];
b.shift().shift(); // 1
// О нет. Теперь на массив "а" относятся также: а
//[[], [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.
Спецификации
Specification |
---|
ECMAScript Language Specification # prod-SpreadElement |
ECMAScript Language Specification # prod-ArgumentList |
ECMAScript Language Specification # prod-PropertyDefinition |
Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
- Rest parameters (also '
...
') - fn.apply (also '
...
')