Классическая проблема

Бывали ли вы когда-нибудь в ситуации, когда вам нужно было создать метод, принимающий неопределенное количество аргументов? Вы бы сказали, что это несложно, поскольку Javascript предоставляет нам всемогущие 'аргументы' как локальные , подобные массиву (обратите внимание - подобный массиву не является массивом ) для использования в каждой функции. Итак, допустим, если мы хотим создать метод для вычисления суммы чисел, не ограничиваясь тем, сколько чисел ему передано, мы можем реализовать как:

function sumOf(){
    var sum = 0; 
    for (var i = 0; i < arguments.length; i++){
         sum += arguments[i];
    }
    
    return sum;
}

Легкая штука, правда? И, конечно же, он отлично работает.

sumOf(1,2,3,4,5);//15
sumOf(1,2);//3

Прохладный. Но ... что, если нам нужен метод, который после этого получает один параметр и неограниченное количество аргументов, потому что мы можем решить только на основе первого аргумента, что делать со всеми другими переданными аргументами (только с ними , не считая первого)? Например:

function execute(action, <param1, param2, param3,...>){
    if (action === <something>){
        doSomething(<param1, param2, param3, ...>)
    }
}

Как этого добиться? Вы можете

Попробуйте применить ()

Функция apply () хороша тем, что apply () принимает в качестве аргументов единственный массив параметров (или объект, подобный массиву), что означает Мы сможем:

Обратной стороной является слишком много работы:

  • Необходимо удалить первый аргумент из списка аргументов.
  • Поскольку аргументы только подобны массиву, отсутствует встроенный shift () или splice (), мы должны сначала преобразовать его в массив, а только затем удалить первый аргумент.

Остальное просто - вызовите действие с помощью apply() и передайте null как значение this и измененный массив.

Вопрос: есть ли более короткий и лучший способ достичь того же результата?

Благодаря ES6 у нас наконец-то появилась магия (…) синтаксиса распространения.

Что такое синтаксис magic spread?

Проще говоря, расширенный синтаксис - записанный как «…» - позволяет:

  • Итерируемый объект
  • Объект выражение

будет расширен в местах, где ожидается:

  • Нуль
  • Неограниченное количество аргументов (вызовы функций)
  • Неограниченное количество элементов (литералы массива)
  • Неограниченное количество пар ключ-значение (объектные литералы)

Как это решает нашу проблему?

Прежде всего, мы можем использовать синтаксис распространения в качестве параметра Rest.

Остаточный параметр

Параметр rest позволяет функции получать неопределенное количество аргументов в виде массива.

функция ‹имя функции› (… аргументы)

Примечание: синтаксис распространения (…) необходимо использовать как префикс для последнего указанного параметра.

В отличие от arguments, параметр Rest:

  • на самом деле является экземплярами Array с полной поддержкой встроенных функций Array.
  • содержит только те, которым не присвоено отдельное имя в качестве элементов массива, а arguments содержит все переданные параметры.
function printMe(a,b,c){
    console.log(arguments); 
    //will print all passed parameters respectively as a, b, c
}
function printMeSpread(a, ...args){
    console.log(args);
    //Will only print from 2nd passed parameters onwards
}
printMe(1,2,3);// [1,2,3]
printMeSpread(1,2,3); //[2,3]

Следовательно, вместо преобразования arguments в массив, удаления первого элемента (который нам не нужен), мы можем просто переписать объявление нашей функции как:

function executeWithSpread(type, ...params){....}

И благодаря этому мы сэкономили около 2–3 строк кода. Что делать дальше?

Избавляемся от apply()

Действительно, мы можем использовать его как замену apply(), тогда наша функция станет:

Здесь, когда мы используем синтаксис «…» в качестве префикса params, все элементы params будут распространяться (расширяться) как аргументы, а не быть одним аргументом params.

Дополнительные пояснения:

  • На executeWithSpread() параметры будут преобразованы в массив, содержащий [1,2,3,4,5], с использованием ...params в объявлении метода.
  • На Sum(), передав параметры как ...params, arguments будет [1,2,3,4,5] вместо [[1,2,3,4,5]]

И, следовательно, нет необходимости в null или в каком-либо дополнительном ненужном шуме.

Но если вы все еще хотите комбинировать с apply(), мы все равно можем сделать следующее:

В любом случае, это еще чище, меньше шансов на ошибку, согласны?

Но не только это, как уже говорилось, синтаксис распространения творит чудеса. Под «магией» я подразумеваю мощный инструмент, несмотря на его внешнюю простоту. Итак…

Что еще он нам предлагает?

Клонировать объект

Один из распространенных способов копирования объекта - использовать Object.assign() для создания неглубокой версии клона.

Синтаксис распространения дает нам более короткий и понятный способ

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

Клонировать массив

Вместо использования поверхностного копирования массива с использованием Array.slice(0)

Или используя Array.from()

Мы можем использовать синтаксис Spread для достижения того же эффекта - но помните, что это будет только один уровень глубины, как Array.slice() и Array.from()

Преобразование итерируемого объекта в массив

Вероятно, многие из нас уже знали и использовали эту функцию 😃 - помните печально известную проблему с удалением дубликатов из заданного массива? 😁

Да, вместо использования цикла для итерации и копирования каждого элемента в новый массив мы можем сократить код, используя синтаксис Spread (…), как указано выше. Он распределит все элементы Set в новый массив соответственно без особых усилий (конечно, меньше шансов для 🐛).

То же самое можно сказать и о преобразовании объекта Map в массив, в котором каждая пара ‹ключ, значение› будет представлена ​​как элемент подмассива в новом массиве.

Но определенно невозможно преобразовать Object, поскольку он не повторяется.

Объединить массивы

Обычно, если мы хотим объединить два или более массивов в один или просто хотим объединить один массив с другим, мы будем использовать

  • Array.prototype.concat(), который вернет новый массив, в котором все элементы дополнительного массива будут добавлены в конец исходного массива. Это не изменит исходный массив.

  • Array.prototype.unshift(), который добавит все элементы дополнительного массива в начало исходного массива. Это действительно изменит исходный массив.

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

Обратите внимание, что в этом случае оба исходных массива не изменяются.

Свойства объектов слияния

Буквально, какой из них вы предпочитаете? Таким образом (который изменяет исходный объект)

for(var key in obj2){
   obj1[key] = obj2[key];
}

Или просто так

Object.assign(obj1, obj2)

Или еще проще? (не изменяет исходный объект)

var mereObj = {...obj1, ...obj2}

Использование с конструктором

При использовании конструктора с синтаксисомnew невозможно напрямую использовать apply() и массив вместе - в ES5, чтобы создать новый массив из существующего массива, нам нужно будет сделать следующее:

var arr = new (Function.prototype.bind.apply(Array, [null].concat([1,2,3,4])));

Разве это не сбивает с толку? По крайней мере, для меня это так. К счастью, для нас есть синтаксис Spread:

var arr = new Array(...[1,2,3,4]);

Разве мы не должны ценить эту магию 😃?

Другое смешанное использование

И последнее, но не менее важное: с помощью синтаксиса Spread мы, наконец, можем получить гораздо более мощный литерал массива, в котором нам не нужно запрашивать помощь дополнительных функций, таких как push, splice, concat и т. Д., Когда это необходимо.

var arr1 = ['hello', 'there'];
var arr2 = ['today', 'is', 'good', 'day', ...arr1, 'how', 'are', 'you']
console.log(arr2); //['today', 'is', 'good', 'day', 'hello', 'there', 'how', 'are', 'you']

Отлично, правда?

И, конечно же, нет ограничений на количество раз, которое мы можем использовать этот синтаксис в литерале массива.

Заключение

Лично я обнаружил, что этот синтаксис скорее полезен, чем следование традиционному способу - , который требует длинной строки кода, и если вы не будете осторожны, вы можете получить 🐛 , не заметив, и что, меня это очень раздражает.

Однако в обмен на чистоту и удобство иногда бывает труднее читать / понимать. (в конце концов, впервые-r (s), кто сможет понять, что означает связка «…»?)

Несмотря на это, как гласит одно из правил №1 в программировании - правило KISS (Keep It Simple Stupid), мы всегда должны стараться, чтобы наш код был как можно проще, и меньше кода но хороший код никогда не бывает плохим (особенно в JS, когда количество строк кода должно быть загружено ДЕЙСТВИТЕЛЬНО имеет значение для веб-производительности).

Так почему не? Если это хорошая магия, нам лучше воспользоваться ею, как лучшим улучшением для нашего собственного волшебного творения. 😄

Вы согласны со мной? Напишите в комментариях. Я хотел бы услышать ваше мнение.

Подробнее о ES6:

Если вам понравился этот пост, не забудьте поставить мне 👏 ниже ⏬️. Это наверняка меня сильно мотивирует 😊

Если вам нравится читать больше, ознакомьтесь с моими статьями.

Если вы хотите иногда меня догнать, подпишитесь на меня в Twitter | Facebook или просто посетите мой сайт портфолио.