Функции
Зачастую нам надо повторять одно и то же действие во многих частях программы.
Например, необходимо красиво вывести сообщение при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.
Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.
Примеры встроенных функций вы уже видели – это alert(message) , prompt(message, default) и confirm(question) . Но можно создавать и свои.
Объявление функции
Для создания функций мы можем использовать объявление функции.
Пример объявления функции:
Вначале идёт ключевое слово function , после него имя функции, затем список параметров в круглых скобках через запятую (в вышеприведённом примере он пустой) и, наконец, код функции, также называемый «телом функции», внутри фигурных скобок.
Наша новая функция может быть вызвана по своему имени: showMessage() .
Вызов showMessage() выполняет код функции. Здесь мы увидим сообщение дважды.
Этот пример явно демонстрирует одно из главных предназначений функций: избавление от дублирования кода.
Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.
Локальные переменные
Переменные, объявленные внутри функции, видны только внутри этой функции.
Внешние переменные
У функции есть доступ к внешним переменным, например:
Функция обладает полным доступом к внешним переменным и может изменять их значение.
Внешняя переменная используется, только если внутри функции нет такой локальной.
Если одноимённая переменная объявляется внутри функции, тогда она перекрывает внешнюю. Например, в коде ниже функция использует локальную переменную userName . Внешняя будет проигнорирована:
Переменные, объявленные снаружи всех функций, такие как внешняя переменная userName в вышеприведённом коде – называются глобальными.
Глобальные переменные видимы для любой функции (если только их не перекрывают одноимённые локальные переменные).
Желательно сводить использование глобальных переменных к минимуму. В современном коде обычно мало или совсем нет глобальных переменных. Хотя они иногда полезны для хранения важнейших «общепроектовых» данных.
Параметры
Мы можем передать внутрь функции любую информацию, используя параметры.
В нижеприведённом примере функции передаются два параметра: from и text .
Когда функция вызывается в строках (*) и (**) , переданные значения копируются в локальные переменные from и text . Затем они используются в теле функции.
Вот ещё один пример: у нас есть переменная from , и мы передаём её функции. Обратите внимание: функция изменяет значение from , но это изменение не видно снаружи. Функция всегда получает только копию значения:
Значение, передаваемое в качестве параметра функции, также называется аргументом.
- Параметр – это переменная, указанная в круглых скобках в объявлении функции.
- Аргумент – это значение, которое передаётся функции при её вызове.
Мы объявляем функции со списком параметров, затем вызываем их, передавая аргументы.
Рассматривая приведённый выше пример, мы могли бы сказать: "функция showMessage объявляется с двумя параметрами, затем вызывается с двумя аргументами: from и "Привет" ".
Значения по умолчанию
Если при вызове функции аргумент не был указан, то его значением становится undefined .
Например, вышеупомянутая функция showMessage(from, text) может быть вызвана с одним аргументом:
Это не приведёт к ошибке. Такой вызов выведет "*Аня*: undefined" . В вызове не указан параметр text , поэтому предполагается, что text === undefined .
Если мы хотим задать параметру text значение по умолчанию, мы должны указать его после = :
Теперь, если параметр text не указан, его значением будет "текст не добавлен"
В данном случае "текст не добавлен" это строка, но на её месте могло бы быть и более сложное выражение, которое бы вычислялось и присваивалось при отсутствии параметра. Например:
В JavaScript параметры по умолчанию вычисляются каждый раз, когда функция вызывается без соответствующего параметра.
В приведённом выше примере, функция anotherFunction() не будет вызвана вообще, если указан параметр text .
С другой стороны, функция будет независимо вызываться каждый раз, когда text отсутствует.
Ранние версии JavaScript не поддерживали параметры по умолчанию. Поэтому существуют альтернативные способы, которые могут встречаться в старых скриптах.
Например, явная проверка на undefined :
…Или с помощью оператора || :
Альтернативные параметры по умолчанию
Иногда имеет смысл присваивать значения по умолчанию для параметров не в объявлении функции, а на более позднем этапе.
Во время выполнения функции мы можем проверить, передан ли параметр, сравнив его с undefined :
…Или мы можем использовать оператор || :
Современные движки JavaScript поддерживают оператор нулевого слияния ?? . Его использование будет лучшей практикой, в случае, если большинство ложных значений, таких как 0 , следует расценивать как «нормальные».
Возврат значения
Функция может вернуть результат, который будет передан в вызвавший её код.
Простейшим примером может служить функция сложения двух чисел:
Директива return может находиться в любом месте тела функции. Как только выполнение доходит до этого места, функция останавливается, и значение возвращается в вызвавший её код (присваивается переменной result выше).
Вызовов return может быть несколько, например:
Возможно использовать return и без значения. Это приведёт к немедленному выходу из функции.
В коде выше, если checkAge(age) вернёт false , showMovie не выполнит alert .
Если функция не возвращает значения, это всё равно, как если бы она возвращала undefined :
Пустой return аналогичен return undefined :
Для длинного выражения в return может быть заманчиво разместить его на нескольких отдельных строках, например так:
Код не выполнится, потому что интерпретатор JavaScript подставит точку с запятой после return . Для него это будет выглядеть так:
Таким образом, это фактически стало пустым return .
Если мы хотим, чтобы возвращаемое выражение занимало несколько строк, нужно начать его на той же строке, что и return . Или, хотя бы, поставить там открывающую скобку, вот так:
И тогда всё сработает, как задумано.
Выбор имени функции
Функция – это действие. Поэтому имя функции обычно является глаголом. Оно должно быть кратким, точным и описывать действие функции, чтобы программист, который будет читать код, получил верное представление о том, что делает функция.
Как правило, используются глагольные префиксы, обозначающие общий характер действия, после которых следует уточнение. Обычно в командах разработчиков действуют соглашения, касающиеся значений этих префиксов.
Например, функции, начинающиеся с "show" обычно что-то показывают.
Функции, начинающиеся с…
- "get…" – возвращают значение,
- "calc…" – что-то вычисляют,
- "create…" – что-то создают,
- "check…" – что-то проверяют и возвращают логическое значение, и т.д.
Примеры таких имён:
Благодаря префиксам, при первом взгляде на имя функции становится понятным, что делает её код, и какое значение она может возвращать.
Функция должна делать только то, что явно подразумевается её названием. И это должно быть одним действием.
Два независимых действия обычно подразумевают две функции, даже если предполагается, что они будут вызываться вместе (в этом случае мы можем создать третью функцию, которая будет их вызывать).
Несколько примеров, которые нарушают это правило:
- getAge – будет плохим выбором, если функция будет выводить alert с возрастом (должна только возвращать его).
- createForm – будет плохим выбором, если функция будет изменять документ, добавляя форму в него (должна только создавать форму и возвращать её).
- checkPermission – будет плохим выбором, если функция будет отображать сообщение с текстом доступ разрешён/запрещён (должна только выполнять проверку и возвращать её результат).
В этих примерах использовались общепринятые смыслы префиксов. Конечно, вы в команде можете договориться о других значениях, но обычно они мало отличаются от общепринятых. В любом случае вы и ваша команда должны чётко понимать, что значит префикс, что функция с ним может делать, а чего не может.
Имена функций, которые используются очень часто, иногда делают сверхкороткими.
Например, фреймворк jQuery определяет функцию с помощью $ . В библиотеке Lodash основная функция представлена именем _ .
Это исключения. В основном имена функций должны быть в меру краткими и описательными.
Функции == Комментарии
Функции должны быть короткими и делать только что-то одно. Если это что-то большое, имеет смысл разбить функцию на несколько меньших. Иногда следовать этому правилу непросто, но это определённо хорошее правило.
Небольшие функции не только облегчают тестирование и отладку – само существование таких функций выполняет роль хороших комментариев!
Например, сравним ниже две функции showPrimes(n) . Каждая из них выводит простое число до n .
Первый вариант использует метку nextPrime :
Второй вариант использует дополнительную функцию isPrime(n) для проверки на простое:
Второй вариант легче для понимания, не правда ли? Вместо куска кода мы видим название действия ( isPrime ). Иногда разработчики называют такой код самодокументируемым.
Таким образом, допустимо создавать функции, даже если мы не планируем повторно использовать их. Такие функции структурируют код и делают его более понятным.
Итого
Объявление функции имеет вид:
- Передаваемые значения копируются в параметры функции и становятся локальными переменными.
- Функции имеют доступ к внешним переменным. Но это работает только изнутри наружу. Код вне функции не имеет доступа к её локальным переменным.
- Функция может возвращать значение. Если этого не происходит, тогда результат равен undefined .
Для того, чтобы сделать код более чистым и понятным, рекомендуется использовать локальные переменные и параметры функций, не пользоваться внешними переменными.
Функция, которая получает параметры, работает с ними и затем возвращает результат, гораздо понятнее функции, вызываемой без параметров, но изменяющей внешние переменные, что чревато побочными эффектами.
- Имя функции должно понятно и чётко отражать, что она делает. Увидев её вызов в коде, вы должны тут же понимать, что она делает, и что возвращает.
- Функция – это действие, поэтому её имя обычно является глаголом.
- Есть много общепринятых префиксов, таких как: create… , show… , get… , check… и т.д. Пользуйтесь ими как подсказками, поясняющими, что делает функция.
Функции являются основными строительными блоками скриптов. Мы рассмотрели лишь основы функций в JavaScript, но уже сейчас можем создавать и использовать их. Это только начало пути. Мы будем неоднократно возвращаться к функциям и изучать их всё более и более глубоко.
Задачи
Обязателен ли "else"?
Следующая функция возвращает true , если параметр age больше 18 .
В ином случае она запрашивает подтверждение через confirm и возвращает его результат:
Будет ли эта функция работать как-то иначе, если убрать else ?
Есть ли хоть одно отличие в поведении этого варианта?
Оба варианта функций работают одинаково, отличий нет.
Перепишите функцию, используя оператор ‘?’ или ‘||’
Следующая функция возвращает true , если параметр age больше 18 .
В ином случае она задаёт вопрос confirm и возвращает его результат.
Перепишите функцию, чтобы она делала то же самое, но без if , в одну строку.
Возврат значений — Основы JavaScript
Функции, которые мы определяли в предыдущих уроках, заканчивали свою работу тем, что печатали на экран какие-то данные:
Пользы от таких функций не очень много, так как результатом их работы невозможно воспользоваться внутри программы. Рассмотрим это на примере.
Возьмем задачу обработки электронной почты. Когда пользователь регистрируется на каком-то сайте, то он может ввести email любым способом:
- Добавив случайно пробелы в начале или в конце _support@hexlet.io__
- Использовав буквы в разном регистре SUPPORT@hexlet.io
Если мы сохраним его в таком виде в базу данных, то пользователь не сможет войти на сайт, если будет вбивать адрес без пробелов и в другом регистре. Чтобы этого не произошло, email нужно подготовить к записи в базу, привести его к нижнему регистру и обрезать пробельные символы по краям строки. Вся задача решается в пару строчек:
Этот код стал возможен только благодаря возврату значения. Методы trim() и toLowerCase() ничего не печатают на экран (в консоль), они возвращают результат своей работы и поэтому мы можем записать его в константы. Если бы они вместо этого печатали на экран, мы бы не могли присвоить результат их работы константе. Как мы не можем сделать с определенной выше функцией greeting() :
Изменим функцию greeting() таким образом, чтобы она начала возвращать данные, вместо их печати. Для этого нам понадобится выполнить возврат вместо печати на экран
return – особая инструкция, которая берет выражение, записанное справа, и отдает его наружу, тому коду, который вызвал функцию. Как только JavaScript натыкается на return , выполнение функции на этом завершается.
Любой код после return не выполняется:
Даже если функция возвращает данные, это не ограничивает ее в том, что она печатает. Кроме возврата данных мы можем и печатать:
Возвращать можно не только конкретное значение. Так как return работает с выражениями, то справа от него может появиться почти все что угодно. Здесь нужно руководствоваться принципами читаемости кода:
Здесь мы не возвращаем переменную, возвращается всегда значение, которое находится в этой переменной. Ниже пример с вычислениями:
Вопрос на самопроверку. Что вернет вызов функции run() , определенной ниже?
Функции вывода
Во время написания программы, а также при её отладке часто возникает необходимость увидеть, как работает программа. Нужно узнать, доходит ли выполнение программы до определённого места и какие значения имеют переменные в этот момент. Для этого существуют функции вывода, которые рассмотрены в данной теме.
Функция alert()
Функция alert() выводит на экран окно с сообщением. Текст сообщения всегда пишется в кавычках. Все функции вывода могут выводить не только текст, но и значения переменных. Пример:
Особенность этой функции заключается в том, что она приостанавливает работу программы. Когда выполнение программы доходит до функции alert() , появляется окно и работа программы прерывается. А когда пользователь нажимает кнопку OK, окно изчезат, а программа продолжает работу. Иногда эта особенность бывает полезна. Она позволяет не только вывести сообщение, но и увидеть, как выглядит страница на данном этапе выполнения программы. Однако, если нужно вывести много сообщений, то использование функции alert() становится неудобным. Ведь при каждом выводе программа прерывается и нужно нажимать кнопку OK. В этих случаях используются другие способы вывода данных.
Метод document.write()
Метод document.write() добавляет текст на страницу. Это может быть не просто текст, но и HTML тэги. Они будут работать. Однако, не рекомендуется использовать этот метод для добавления элементов страницы. Они могут отображаться неправильно. Для создания элементов применяются другие методы, которые рассмотрены в этом учебнике. А document.write() используется, в основном, для отслеживания работы программы. Пример:
Метод console.log()
Консоль браузера — это полезный инструмент отладки страницы, в том числе, скриптов. Он позволяет получить важную информацию о работе скрипта. Удобнее всего консоль сделана в браузере FireFox. Она находится в Инструментах разработчика. Чтобы их открыть, зайдите в главное меню браузера и выберите «Другие интструменты». Для быстрого открытия Инструментов разработчика можно добавить кнопку в панель инструментов.
Шпаргалка по JavaScript №2 — Вывод информации.
В этой главе будет рассказано о методах вывода информации силами ActionScript. По традиции в качестве выводимых данных используется строка “Hello World”. В данной же статье мы выведем на экран эту строку тремя разными способами.
Первый вариант вывода информации (функция writeln).
Самый простой и популярный способ вывести информацию на экран – это функция document.writeln(string). Нижу приведен пример:
После вызова этой функции все прежде существующее содержимое страницы будет заменено на новое. В данном случае на строку “Hello World”. Поэтому рекомендуется использовать эту функцию только при загрузке страницы, если все содержимое создается усилиями JavaScript. Также эта функция очень полезная в ситуациях, когда необходимо сократить количество обращений к серверу. Один раз скачанный файл с исходным кодом может порождать несколько различных страниц в полностью автономном режиме.
Второй вариант вывода информации (функция alert).
Функция alert(string) очень хорошо подходит для отладки кода, но не для конечного использования. После ее вызова перед пользователем появится окошко с надписью и кнопкой “Ok”. Рекомендуется не использовать подобные всплывающие окна в реальных веб-сайтах, так как они очень сильно раздражают посетителей и часто блокируются различными плагинами браузера. Пример использования функции для отладки:
После выполнения этого когда перед вами появится стандартное окно Windows (или Linux, или Mac OS) всего лишь с одним вариантом ответа. Никакие взаимодействия со страницей до нажатия на кнопку “Ok” невозможны.
Третий вариант вывода информации (функция getElementById).
Самый мощный и часто используемый способ – это использование функции getElementById(tagId).
Далее важный абзац, который стоит читать медленно и вдумчиво.
Все в HTML коде может иметь параметр ID. Любой тэг имеет вложенную в него строку (строка может быть и пустой). Через ID тэга можно обратиться к его содержимому и, соответственно, изменить. При этом другие тэги затронуты не будут. Пример:
В этом коде первым делом будет сделано обращение к документу (document), затем взят указатель на элемент-тэг, имеющий id равный “placeForText” (getElementById(“placeForText”)), а после, с помощью функции innerHTML, взят указатель на содержимое этого элемента-тэга. Используя равенство мы присваиваем содержимому элемента новое значение.
Такой подход намного лучше двух предыдущих по двум причинам: отсутствие назойливых всплывающих сообщений, возможность редактировать только часть HTML страницы. Естественно, при использовании такой функции возможен и следующий вариант:
При выполнении этого кода внутрь элемента <div> будет вставлен отформатированный текст с использованием HTML тэгов. То есть мы вставляем HTML внутрь HTML. На экране появится уже привычный нам текст “Hello World!”, однако написан он будет красным цветом.
Такой же механизм использован на страницах с регистрацией новых пользователей. На странице расположены две ключевых области: одна пустая, вторая с формой, которую необходимо заполнить. Если пользователь пропускает какое-нибудь поле или вводит неправильную информацию и пытается отправить форму на сервер, то скрипт, ответственный за валидацию введенных данных, обнаруживает ошибку и выводит красную надпись в пустую область, не модифицируя остальную страницу.
В этой статье были разобраны все основные варианты вывода текста (чисел и других переменных, представимых в текстовом виде) на экран. В следующей статье “Шпаргалка по JavaScript №3 – Ввод информации” будет рассказано об обратном процессе.