Зачастую нам надо повторять одно и то же действие во многих частях программы.
Например, красиво вывести сообщение необходимо при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.
Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.
Примеры встроенных функций вы уже видели – это alert(message)
, prompt(message, default)
и confirm(question)
. Но можно создавать и свои.
Пример объявления функции:
Вначале идет ключевое слово function
, после него имя функции, затем список параметров в скобках (в примере выше он пустой) и тело функции – код, который выполняется при её вызове.
Объявленная функция доступна по имени, например:
Этот код выведет сообщение два раза. Уже здесь видна главная цель создания функций: избавление от дублирования кода.
Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.
Функция может содержать локальные переменные, объявленные через var
. Такие переменные видны только внутри функции:
Блоки if/else
, switch
, for
, while
, do..while
не влияют на область видимости переменных.
При объявлении переменной в таких блоках, она всё равно будет видна во всей функции.
Например:
Неважно, где именно в функции и сколько раз объявляется переменная. Любое объявление срабатывает один раз и распространяется на всю функцию.
Объявления переменных в примере выше можно передвинуть вверх, это ни на что не повлияет:
Функция может обратиться ко внешней переменной, например:
Доступ возможен не только на чтение, но и на запись. При этом, так как переменная внешняя, то изменения будут видны и снаружи функции:
Конечно, если бы внутри функции, в строке (1)
, была бы объявлена своя локальная переменная var userName
, то все обращения использовали бы её, и внешняя переменная осталась бы неизменной.
Переменные, объявленные на уровне всего скрипта, называют «глобальными переменными».
В примере выше переменная userName
– глобальная.
Делайте глобальными только те переменные, которые действительно имеют общее значение для вашего проекта, а нужные для решения конкретной задачи – пусть будут локальными в соответствующей функции.
В старом стандарте JavaScript существовала возможность неявного объявления переменных присвоением значения.
Например:
В коде выше переменная message
нигде не объявлена, а сразу присваивается. Скорее всего, программист просто забыл поставить var
.
При use strict
такой код привёл бы к ошибке, но без него переменная будет создана автоматически, причём в примере выше она создаётся не в функции, а на уровне всего скрипта.
Избегайте этого.
Здесь опасность даже не в автоматическом создании переменной, а в том, что глобальные переменные должны использоваться тогда, когда действительно нужны «общескриптовые» параметры.
Забыли var
в одном месте, потом в другом – в результате одна функция неожиданно поменяла глобальную переменную, которую использует другая. И поди разберись, кто и когда её поменял, не самая приятная ошибка для отладки.
В будущем, когда мы лучше познакомимся с основами JavaScript, в главе Замыкания, функции изнутри, мы более детально рассмотрим внутренние механизмы работы переменных и функций.
При вызове функции ей можно передать данные, которые та использует по своему усмотрению.
Например, этот код выводит два сообщения:
Параметры копируются в локальные переменные функции.
Например, в коде ниже есть внешняя переменная from
, значение которой при запуске функции копируется в параметр функции с тем же именем. Далее функция работает уже с параметром:
Функцию можно вызвать с любым количеством аргументов.
Если параметр не передан при вызове – он считается равным undefined
.
Например, функцию показа сообщения showMessage(from, text)
можно вызвать с одним аргументом:
При этом можно проверить, и если параметр не передан – присвоить ему значение «по умолчанию»:
При объявлении функции необязательные аргументы, как правило, располагают в конце списка.
Для указания значения «по умолчанию», то есть, такого, которое используется, если аргумент не указан, используется два способа:
Можно проверить, равен ли аргумент undefined
, и если да – то записать в него значение по умолчанию. Этот способ продемонстрирован в примере выше.
Использовать оператор ||
:
Второй способ считает, что аргумент отсутствует, если передана пустая строка, 0
, или вообще любое значение, которое в логическом контексте является false
.
Если аргументов передано больше, чем надо, например showMessage("Маша", "привет", 1, 2, 3)
, то ошибки не будет. Но, чтобы получить такие «лишние» аргументы, нужно будет прочитать их из специального объекта arguments
, который мы рассмотрим в главе Псевдомассив аргументов "arguments".
Функция может возвратить результат, который будет передан в вызвавший её код.
Например, создадим функцию calcD
, которая будет возвращать дискриминант квадратного уравнения по формуле b2 – 4ac
:
Для возврата значения используется директива return
.
Она может находиться в любом месте функции. Как только до неё доходит управление – функция завершается и значение передается обратно.
Вызовов return
может быть и несколько, например:
Директива return
может также использоваться без значения, чтобы прекратить выполнение и выйти из функции.
Например:
В коде выше, если сработал if
, то строка (*)
и весь код под ней никогда не выполнится, так как return
завершает выполнение функции.
return
и с пустым return
В случае, когда функция не вернула значение или return
был без аргументов, считается что она вернула undefined
:
Обратите внимание, никакой ошибки нет. Просто возвращается undefined
.
Ещё пример, на этот раз с return
без аргумента:
Имя функции следует тем же правилам, что и имя переменной. Основное отличие – оно должно быть глаголом, т.к. функция – это действие.
Как правило, используются глагольные префиксы, обозначающие общий характер действия, после которых следует уточнение.
Функции, которые начинаются с "show"
– что-то показывают:
Функции, начинающиеся с "get"
– получают, и т.п.:
Это очень удобно, поскольку взглянув на функцию – мы уже примерно представляем, что она делает, даже если функцию написал совсем другой человек, а в отдельных случаях – и какого вида значение она возвращает.
Функция должна делать только то, что явно подразумевается её названием. И это должно быть одно действие.
Если оно сложное и подразумевает поддействия – может быть имеет смысл выделить их в отдельные функции? Зачастую это имеет смысл, чтобы лучше структурировать код.
…Но самое главное – в функции не должно быть ничего, кроме самого действия и поддействий, неразрывно связанных с ним.
Например, функция проверки данных (скажем, "validate"
) не должна показывать сообщение об ошибке. Её действие – проверить.
Объявление функции имеет вид:
var
.return ...
.return
тут же прекращает функцию.return;
вызван без значения, или функция завершилась без return
, то её результат равен undefined
.При обращении к необъявленной переменной функция будет искать внешнюю переменную с таким именем, но лучше, если функция использует только локальные переменные:
Именование функций:
Функции являются основными строительными блоками скриптов. Мы будем неоднократно возвращаться к ним и изучать все более и более глубоко.