Синтаксис распространения ES6
Рассмотрим следующий пример кода
var x = ["a", "b", "c"];
var z = ["p", "q"];
var d = [...x, ...z];
var e = x.concat(z);
Здесь значение d
и e
точно такое же и равно ["a", "b", "c", "p", "q"]
, поэтому
- В чем же разница между этими двумя?
- Какой из них более эффективен и почему?
- Что такое использование синтаксиса распространения?
Разве вы не думаете, что введение этих небольших ярлыков на формальном обширном языке может оставить некоторые незаметные ошибки, я имею в виду, что это довольно необязательно, или я не понимаю, что это нужно должным образом.
Ответы
Ответ 1
- В приведенном вами примере нет никакой разницы между двумя
.concat
значительно более эффективен: http://jsperf.com/spread-into-array-vs-concat, потому что ...
(распространение) является просто синтаксическим сахаром поверх более фундаментального базового синтаксиса, который явно перебирает индексы для расширения массива.
- Spread допускает использование подслащенного синтаксиса в дополнение к более громоздким прямым манипуляциям с массивами
Если говорить о № 3 выше, то использование вами распространения является несколько надуманным примером (хотя и часто встречающимся в дикой природе). Распространение полезно, когда, например, весь список аргументов должен быть передан .call
в теле функции.
function myFunc(){
otherFunc.call( myObj, ...args );
}
против
function myFunc(){
otherFunc.call( myObj, args[0], args[1], args[2], args[3], args[4] );
}
Это еще один произвольный пример, но немного понятнее, почему оператор распространения будет хорошо использовать в некоторых других подробных и неуклюжих ситуациях.
Как указывает @loganfsmyth points out:
Spread также работает с произвольными итерируемыми объектами, что означает, что он работает не только с Array
, но также с Map
и Set
.
Это замечательный момент, который дополняет идею о том, что, хотя в ES5 это невозможно сделать, функциональность, представленная в операторе распространения, является одним из наиболее полезных элементов в новом синтаксисе.
Фактический базовый синтаксис для оператора распространения в этом конкретном контексте (поскольку ...
также может быть параметром "отдыха"), см. в спецификации. "более фундаментального базового синтаксиса, который явно перебирает индексы для расширения массива", как я писал выше, достаточно, чтобы понять суть, но фактическое определение использует GetValue
и GetIterator
для следующей переменной.
Ответ 2
Вывод этого примера такой же, но его поведение не совпадает,
Рассмотрим (проверьте консоль браузера):
var x = [], y = [];
x[1] = "a";
y[1] = "b";
var usingSpread = [...x, ...y];
var usingConcat = x.concat(y);
console.log(usingSpread); // [ undefined, "a", undefined, "b"]
console.log(usingConcat); // [ , "a", , "b"]
console.log(1 in usingSpread); // true
console.log(1 in usingConcat); // false
Array.prototype.concat сохранит пустые слоты в массиве, а Spread заменит их значениями undefined
.
Введите Symbol.iterator и Symbol.isConcatSpreadable :
Оператор Spread использует символ @@iterator
для перебора массивов и объектов, похожих на массивы, таких как:
- Array.prototype
- TypedArray.prototype
- String.prototype
- Map.prototype
- Set.prototype
(вот почему вы можете использовать for .. of
на них)
Мы можем переопределить символ iterator
по умолчанию, чтобы увидеть, как ведет себя оператор spread
:
var myIterable = ["a", "b", "c"];
var myIterable2 = ["d", "e", "f"];
myIterable[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
};
console.log(myIterable[0], myIterable[1], myIterable[2]); // a b c
console.log([...myIterable]); // [1,2,3]
var result = [...myIterable, ...myIterable2];
console.log(result); // [1,2,3,"d","e","f"]
var result2 = myIterable.concat(myIterable2);
console.log(result2); // ["a", "b", "c", "d", "e", "f"]
Ответ 3
Разбирая вопросы по порядку, давайте начнем с фундаментального вопроса: что такое использование распространенного синтаксиса?
Синтаксис Spread в основном распаковывает элементы итерируемого объекта, такие как массив или объект. Или для более подробного объяснения из MDN Web Docs о распространенном синтаксисе:
Распространенный синтаксис допускает итерацию, такую как выражение массива или строка быть развернутым в местах, где ноль или более аргументов (для функции ожидаются) или элементы (для литералов массива), или объект выражение, которое будет раскрыто в местах, где ноль или более пар ключ-значение (для объектных литералов).
Ниже приведены несколько простых примеров типичных сценариев использования для расширенного синтаксиса и пример различия между расширенным синтаксисом и параметрами остальных (они могут выглядеть одинаково, но они выполняют почти противоположные функции).
Вызов функции:
const multiArgs = (one, two) => {
console.log(one, two);
}
let args = [1, 2];
multiArgs(...args);
// 1 2
Ответ 4
Нет никакой разницы между этими двумя в данном примере. Для объединения мы можем использовать метод concat для оператора распространения. Однако использование оператора распространения не ограничивается объединением массивов.
Синтаксис расширения позволяет расширять итерацию, например выражение массива или строку. Его можно использовать в следующих сценариях.
Оператор распространения с массивами
- Конкатенация массивов
- Строка в массив
- Массив как аргументы для работы.
Оператор распространения с объектами
Чтобы увидеть демонстрацию всех этих применений и попробовать свои силы в коде, перейдите по ссылке ниже (codepen.io)
ES6-Демонстрация оператора спреда
/**
* Example-1: Showing How Spread Operator can be used to concat two or more
arrays.
*/
const americas = ['South America', 'North America'];
const eurasia = ['Europe', 'Asia'];
const world = [...americas, ...eurasia];
/**
* Example-2: How Spread Operator can be used for string to array.
*/
const iLiveIn = 'Asia';
const iLiveIntoArray = [...iLiveIn];
/**
* Example-3: Using Spread Operator to pass arguments to function
*/
const numbers = [1,4,5];
const add = function(n1,n2,n3){
return n1 + n2 + n3;
};
const addition = add(numbers[0],numbers[1],numbers[2]);
const additionUsingSpread = add(...numbers);
/**
* Example-4: Spread Operator, can be used to concat the array
*/
const personalDetails = {
name: 'Ravi',
age: '28',
sex: 'male'
};
const professionalDetails = {
occupation: 'Software Engineer',
workExperience: '4 years'
};
const completeDetails = {...personalDetails, ...professionalDetails};