Функции
Last updated
Last updated
Очень часто при создании программ участок кода повторяется. А если программа большая, то возникает необходимость повторно использовать подобные участки кода, зачастую с новыми начальными значениями. Воплощением этой идеи являются функции.
Функция - это подпрограмма, независимая часть кода, предназначенная для выполнения конкретной задачи.
Функции можно представить как черный ящик, они получают что-то на входе (данные), и отдают что-то на выходе (результат выполнения кода внутри функции).
Функции - это инструмент для структурирования больших программ, уменьшения повторений и изолирования кода.
Функциональное выражение (function expression) — обычное объявление переменной, значение которой будет функция.
Объявим переменную add
, и присвоим ей функцию, принимающую 3 значения и возвращающую результат сложения этих значений.
Имя функции - это действие, глагол начинающийся с маленькой буквы, отвечающий на вопрос 'Что сделать?'
. Например: findSmallesNumber
, fetchUserInfo
, validateInput
.
Определение функции начинается с ключевого слова function
, за которым может следовать необязательное имя функции. В круглых скобках идут параметры — перечисление данных, которые функция будет получать из вне. Параметров может быть несколько или вообще ни одного, тогда записываются просто пустые круглые скобки ()
.
Далее идет тело функции, заключенное в фигурные скобки {}
, содержащее инструкции, которые необходимо выполнить при вызове функции. Тело функции всегда заключают в фигурные скобки, даже если оно состоит из одной инструкции.
Оператор return
определяет возвращаемое значение. Когда интерпретатор доходит до return
, он сразу же выходит из функции, и возвращает это значение в то место кода, где функция была вызвана.
Оператор return
без выражения возвращает значение undefined
. При отсутствии return
в теле функции, она все равно вернет значение undefined
.
Затем, когда необходимо, функция вызывается с помощью имени и круглых скобок, внутри которых могут быть переданы аргументы.
Термин аргументы используется при вызове функции, когда мы передаем значения в функцию.
Термин параметры используется при объявлении функции, это те локальные переменные внутри функции, в которые будут записаны значения аргументов во время ее вызова.
В JavaScript важен порядок объявления параметров функции. Не существует никакого другого механизма пояснить интерпретатору как значения аргументов функции при вызове связаны с параметрами.
Порядок объявления параметров соответствует порядку передачи аргументов при вызове функции: значение первого аргумента будет присвоено первому параметру, второго аргумента - второму параметру и т. д. Если параметров будет меньше чем аргументов, то параметрам без значений будет присвоено undefined
.
Функция может либо вызвать побочные эффекты (изменять глобальные переменные), либо возвращать результат своей работы. В зависимости от того, какой фрагмент кода будет помещен внутри функции, произойдет либо возврат вычисленного значения, либо изменение состояния программы, а иногда и оба действия.
Если при выполнении кода, интерпретатор встречает вызов функции, он приостанавливает выполнение текущего кода и начинает выполнять код из тела функции. После того как весь код функции будет выполнен, интерпретатор выходит из тела функции, возвращаясь в то место, откуда пришел и продолжает выполнять код, следующий ниже вызова функции.
Пошагово разберем выполнение кода примера:
При входе в js-файл, код начинает выполняться сверху вниз.
Вызов fnA()
заставляет интерпретатор приостановить исполнение кода и зайти в тело функции fnA
.
В функции fnA
интерпретатор встречает вызов функции fnB
, которая перехватывает контроль и исполняется.
Как только интерпретатор выполнил функцию fnB
, то есть в ней произошел return
, в нашем случае не явный, интерпретатор возвращается в функцию fnA
и продолжает выполнять ее с того места где остановился.
Как только интерпретатор выполнил функцию fnA
, то есть в ней произошел return
, в нашем случае не явный, интерпретатор возвращается в глобальный код и продолжает его выполнение.
При вызове функции необязательно указывать значения всех аргументов, которые перечислены в параметрах функции. Но иногда параметрам, которым не передали значение через аргумент бывает необходимо присвоить какое-то значение, отличное от undefined
.
Новые возможности ES6 позволяют сделать это очень простым и очевидным образом, указывая значение по умолчанию прямо при объявлении параметров в подписи функции. При такой записи, если значение переданного аргумента равно undefined
, в параметр записывается значение по умолчанию.
Доступ к набору всех аргументов можно получить через специальную локальную переменную arguments
, которая доступна только внутри функции и хранит все аргументы как псевдомассив.
Псевдомассив — коллекция, имеющая свойство length
и возможность обратиться к элементу по индексу, но отсутствием большинства методов для работы с массивом.
Псевдомассив arguments
содержит список аргументов, переданных функции при вызове, но количество переданных аргументов может не совпадать с количеством объявленных параметров и это не приведет к ошибке.
Рассмотрим пример использования arguments
в функции, которая суммирует любое количество аргументов:
Так как у псевдомассив нет методов типа slice()
или includes()
, часто необходимо преобразовать его в полноценный массив. На практике используют несколько основных способов преобразования.
Используя метод Array.from()
, который создаст массив из итерируемого объекта.
Используя операцию ...
(rest), она позволяет собрать произвольное количество элементов, в нашем случае аргументов, в массив и сохранить его в переменную. Собираем все аргументы используя операцию rest
прямо в подписи функции.
Оператор if...else
- это основной способ создания логических деревьев. Тем не менее, сложные вложенные ветвления делают код более запутанным и трудным для понимания.
Создадим функцию, которая обрабатывает снятие денег с личного счета в банке. Функция получает сумму для снятия и текущий баланс счета, после чего, в зависимости от условия, выполняет тот или иной блок кода.
Даже в таком простом примере есть группа вложенных условных операторов, среди которых не сразу можно выделить нормальный ход выполнения кода из-за особенности синтаксиса if...else
.
Паттерн guard clause - это способ использовать возможность досрочного возврата из функции с помощью оператора return
, чтобы сделать вложенные условные выражения более одномерными.
Выделим все проверки условий в отдельные операторы if
, после чего добавим код, идущий в теле else
. В идеальном случае, должен получиться плоский список условных операторов, идущих один за другим, а в конце блок, который выполнится только в том случае, если не выполнится ни один if
.
Используя такой подход, получаем более чистый, плоский и понятный код, который легче рефакторить.
Другой способ создать функцию — использовать ключевое слово function
в начале инструкции. Такая запись называется объявление функции (function declaration).
Инструкция определяет переменную add
и присваивает ей заданную функцию. Эта форма записи не требует обязательной точки с запятой после закрытия фигурной скобки тела функции.
С другой стороны, при таком синтаксисе может быть сложно отследить связь между местом объявления функции и местом ее вызова. Современные гайды по стилю кода, составленные большими компаниями с многолетним опытом разработки, так же склоняются к использованию функциональных выражений. Поэтому рекомендуется использовать функциональные выражения, вместо объявлений функции.
Стрелочные функции имеют сокращенный, более лаконичный синтаксис и некоторые особенности. Подобно функциональным выражениям, они присваиваются переменным или могут быть анонимными. Их использование очень удобно и значительно сокращает объемы кода, особенно когда функция маленькая.
Все стрелки создаются с помощью функционального выражения, если функция не анонимна, то она должна быть присвоена переменной. Поэтому следует помнить, что перед использованием стрелочной функции её всегда необходимо создать заранее.
Слово function
не используется, вместо этого сразу идет объявление параметров, за которыми всегда следует символ =>
.
После =>
идет тело функции. Здесь может быть два варианта: с фигурными скобками или без них.
У стрелочных функций нет локальной переменной arguments
, содержащей все аргументы. Если необходимо собрать все аргументы в массив, используется операция rest
.
Особенностью этого синтаксиса является то, что функцию можно вызвать до ее объявления в коде. Это может быть удобно, потому что не нужно беспокоиться о необходимости определять все функции выше того места, где они используются. Механизм поднятия идентификаторов описан .