Итак, давайте обсудим то, как работать с аргументами. Для этого рассмотрим следующий пример. Напишем функцию вычисления минимума двух чисел. Назовем ее «функция min», и она принимает два аргумента — a и b. Если a < b, то минимумом будет a, иначе, минимум — b. Эта функция работает следующим образом: если вызвать ее от двух аргументов, то вернется минимальный, то есть из 2 и 7 мы выберем 2. Если вызвать эту функцию от трех аргументов, то в отличие от многих других языков программирования, ошибки не произойдет. Эта функция вызовется, и в качестве переменной a будет лежать 3, b — 4, а 2 мы просто проигнорируем. Если же вызвать эту функцию с одним аргументом, то произойдет следующее. В a мы положим 13, а b будет не определено, то есть undefined. Сравнивая что-нибудь с undefined, мы всегда получаем «ложь». Соответственно, вернем мы b, то есть undefined. Как же сделать так, чтобы, вызывая функцию от одного аргумента, мы получали этот самый аргумент? Самое простое решение — это взять и инвертировать условие, то есть спрашивать не a < b, а a > b. Тогда функция будет работать так: вызывая ее от двух аргументов, мы по-прежнему будем получать минимум, а если вызываем ее с одним аргументом (13), то сравнивая с undefined, получаем «ложь» и возвращаем первый аргумент 13. Но не всегда так получается — взять, инвертировать условие, и все работает правильно. В общем случае нужно проверять, явно передали мы аргументы или нет, то есть сравнивать аргумент с undefined. В нашем случае, если аргумент b = undefined, то нужно вернуть a — минимальное значение. Иначе воспользоваться старой логикой и сравнить a и b. Такой подход тоже работает правильно, если мы передаем два аргумента, то вычисляем минимум из них, если передаем один аргумент, то возвращаем его — 13. В предыдущем примере проверка значения аргумента занимала большую часть функции. Хочется написать этот код компактнее. Это можно сделать при помощи оператора «или». Он работает таким образом: если аргумент b передали, тогда b или Infinity вернет то, что лежит в b. То есть в нашем случае с 2 и 7 в b окажется 7. Если аргумент b не передали, то есть он равен undefined, то оператор b или Infinity вернет бесконечность, и в b окажется бесконечность. Таким образом, мы можем неявно задать значение аргумента b. Использовать оператор «или» достаточно опасно, и во многих случаях он может сыграть с вами злую шутку. Давайте рассмотрим на примере. Объявим функцию getCost, которая вычисляет стоимость товара – это количество товара, умноженное на цену. И по умолчанию мы будем считать, что если количество товара не передали, то оно равно единице. Работает это все достаточно ожидаемым образом. Если мы передаем количество, мы перемножаем цену на количество, если нет, то умножаем на единицу, и все хорошо до тех пор, пока мы не передаем в качестве количества 0. 0 неявно приводится к false, поэтому оператор «или» будет вести себя так: 0 или 1 вернет 1, и мы получим не то, что ожидали. В данном примере лучше всего использовать явное сравнение с undefined. Чтобы пример работал правильно, давайте перепишем его так. Мы явно сравниваем количество товара с undefined. Если количество товара не определено, присваиваем значение 1. Иначе оставляем переданное значение. И этот пример работает уже правильно ожидаемым образом. Еще один способ работы с аргументами называется «именованные аргументы». И давайте рассмотрим его на примере функции вычисления индекса массы тела. Эта функция принимает один-единственный аргумент params, а всё, что нам нужно, мы достаем из этого аргумента следующим образом: params, точка и имя аргумента. Для вычисления индекса массы тела, нам нужно узнать рост человека и его вес. Соответственно, чтобы воспользоваться этой функцией, мы вызываем ее с одним-единственным аргументом — объектом, свойства которого — это наш аргумент. Этот подход обладает рядом преимуществ. Удобнее всего его использовать, если у вас много необязательных аргументов. Вы можете вызвать функцию, передав в объект только нужные аргументы, а все остальные оставить за кадром. Кроме того, удобнее использовать его, когда порядок аргументов неважен или аргументов настолько много, что перечислять их через запятую неудобно. Такой код становится легко рефакторить: если вы написали все ваши функции с использованием подхода «именнованные аргументы», то вам не составит труда добавить или удалить аргумент из цепочки вызовов. Однако у такого подхода есть ряд недостатков. И самый главный из них заключается в том, что глядя на функцию, мы не знаем заранее, какие аргументы нужно туда передать, чтобы функция отработала правильно. Внутри самой функции нам становится менее удобно работать с аргументами. Для того чтобы получить доступ к аргументу, мы вызываем params, точка, имя аргумента. Вы, наверное, обратили внимание: в предыдущем примере мне пришлось вынести рост человека в переменную, чтобы функция вычисления индекса массы тела влезла в экран. Следующий способ работы с аргументами — это использование переменной arguments. Arguments — это подобный массиву объект, содержащий в себе массив аргументов, которые передали в функцию. У этого объекта есть свойство length, которое указывает количество аргументов, переданных в функцию, а также мы можем обратиться по индексу к каждому конкретному аргументу. Давайте рассмотрим использование объекта arguments на следующем примере. Объявим функцию sum, которая складывает два числа. Первое число a мы получим из arguments с индексом 0 из первого аргумента функции. Если его не передали, то при помощи оператора «или» положим в переменную a значение 0. Аналогичным образом поступаем для переменной b. И в результате складываем два числа. Если передать два аргумента, например, 3 и 12, то мы получим сумму этих двух чисел. Если мы передадим один аргумент, то за счет оператора «или» в переменной b будет лежать 0, и мы получим правильное значение 45. Если мы вызываем эту функцию от трех аргументов, то последний аргумент, третий аргумент, проигнорируется, и мы получим сумму первых двух чисел. Давайте модернизируем нашу функцию сложения чисел таким образом, чтобы она вычисляла сумму произвольного числа аргументов. Для этого воспользуемся свойством length, которое есть у arguments. Наш код мы перепишем так: создадим некоторую переменную sum — аккумулятор, куда мы будем складывать сумму, и пробежимся по массиву аргументов следующим образом. При помощи оператора for говорим: пробежимся от нулевого индекса до arguments length, то есть до последнего аргумента, и все эти аргументы будем складывать в наш аккумулятор sum, который в конце функции вернем. Таким образом, наша функция будет складывать произвольное количество аргументов. Arguments — это не массив, однако мы можем привести его к массиву, воспользуясь методом slice. Заимствуя метод slice у массива и вызывая его от лица arguments при помощи метода call, мы получаем в переменной args массив, на котором вызываем метод reduce. В этот метод нужно передать два аргумента: call back и начальное значение. Если мы пропускаем начальное значение, то call back будет вызван от второго аргумента, в качестве начального значения будет использован первый элемент массива. Таким образом, наша функция будет по-прежнему правильно работать, складывая все переданные аргументы. Метод call в предыдущем примере нам нужен был для того, чтобы вызвать метод slice от лица объекта arguments. Давайте рассмотрим подробнее, как работает этот подход. Если мы позовем метод slice у массива, не передавая туда аргументов, то мы получим копию исходного массива. Помимо прямого вызова метода slice, то есть записи «массив, точка, slice, круглые скобочки», мы можем вызвать метод slice, используя метод функции call, передавая туда единственный аргумент, исходный массив. Тогда мы получим копию этого исходного массива. Помимо массивов, slice может принимать массивоподобные объекты. коим и является наш объект arguments. В этом видео мы разобрали с вами несколько способов работы с аргументами, поняли, как можно задать дефолтное значение аргументов, разобрали, что такое именованные аргументы и массивоподобный объект arguments.