Почему функция «возвращает» значение?

Изучающие программирование часто удивляются: почему функция «возвращает» результат? Почему именно такое странное слово — «возврат»? Как будто мы сначала даём ей результат, а потом она его возвращает обратно.
Понятно, что это не так. Мы даём функции аргументы (а иногда и вообще не даём ничего), а она даёт нам в ответ какую-то информацию… А иногда не даёт! Тогда мы говорим «она ничего не возвратила».
Дело в том, что return означает не возврат информации, а возврат управления.
При вызове функции текущий код становится на паузу и передаёт управление в функцию. Функция делает свои дела и возвращает управление в то место, где происходил вызов. И заодно может отправить какую-то информацию туда.
Что за управление? Управление той штукой, которая исполняет код. Грубо говоря — управление компьютером. Код передаёт функции пульт управления компьютером, а функция потом возвращает его обратно.
Мы привыкли читать подобный код как «функция возвращает значение answer », но правильнее будет читать «функция возвращает управление в место вызова и отправляет туда значение answer».
Именно поэтому внутри функции возможен такой код:
Здесь функция не «возвращает ничего», а «возвращает управление в место вызова и не отправляет туда никакую информацию».
Конечно, такая формулировка хоть и технически более корректна, в реальной жизни нет смысла отказываться от «возвращает значение». Это, можно сказать, общепринятое сокращение.
Полезная информация Начните изучать разработку с бесплатного курса «Основы современной вёрстки». Вы научитесь создавать статические веб-страницы, стилизовать элементы, использовать редакторы кода с полезными расширениями. В конце курса вы опубликуете свой первый сайт на GitHub Pages.
Почему функция «возвращает» значение?
Изучающие программирование часто удивляются: почему функция «возвращает» результат? Почему именно такое странное слово — «возврат»? Как будто мы сначала даём ей результат, а потом она его возвращает обратно.
Понятно, что это не так. Мы даём функции аргументы (а иногда и вообще не даём ничего), а она даёт нам в ответ какую-то информацию… А иногда не даёт! Тогда мы говорим «она ничего не возвратила».
Дело в том, что return означает не возврат информации, а возврат управления.
При вызове функции текущий код становится на паузу и передаёт управление в функцию. Функция делает свои дела и возвращает управление в то место, где происходил вызов. И заодно может отправить какую-то информацию туда.
Что за управление? Управление той штукой, которая исполняет код. Грубо говоря — управление компьютером. Код передаёт функции пульт управления компьютером, а функция потом возвращает его обратно.
Мы привыкли читать подобный код как «функция возвращает значение answer », но правильнее будет читать «функция возвращает управление в место вызова и отправляет туда значение answer».
Именно поэтому внутри функции возможен такой код:
Здесь функция не «возвращает ничего», а «возвращает управление в место вызова и не отправляет туда никакую информацию».
Конечно, такая формулировка хоть и технически более корректна, в реальной жизни нет смысла отказываться от «возвращает значение». Это, можно сказать, общепринятое сокращение.
Урок №12. Функции
Вы уже знаете, что каждая программа должна содержать функцию main() (с которой она и начинает свое выполнение). Тем не менее, большинство программ используют и много других функций.
Функции
Функция — это последовательность стейтментов для выполнения определенного задания. Часто ваши программы будут прерывать выполнение одних функций ради выполнения других. Вы делаете аналогичные вещи в реальной жизни постоянно. Например, вы читаете книгу и вспомнили, что должны были сделать телефонный звонок. Вы оставляете закладку в своей книге, берете телефон и набираете номер. После того, как вы уже поговорили, вы возвращаетесь к чтению: к той странице, на которой остановились.
Программы на языке C++ работают похожим образом. Иногда, когда программа выполняет код, она может столкнуться с вызовом функции. Вызов функции — это выражение, которое указывает процессору прервать выполнение текущей функции и приступить к выполнению другой функции. Процессор «оставляет закладку» в текущей точке выполнения, а затем выполняет вызываемую функцию. Когда выполнение вызываемой функции завершено, процессор возвращается к закладке и возобновляет выполнение прерванной функции.
Функция, в которой находится вызов, называется caller, а функция, которую вызывают — вызываемая функция, например:
Результат выполнения программы:
Starting main()
In doPrint()
Ending main()
Эта программа начинает выполнение с первой строки функции main(), где выводится на экран следующая строка: Starting main() . Вторая строка функции main() вызывает функцию doPrint(). На этом этапе выполнение стейтментов в функции main() приостанавливается и процессор переходит к выполнению стейтментов внутри функции doPrint(). Первая (и единственная) строка в doPrint() выводит текст In doPrint() . Когда процессор завершает выполнение doPrint(), он возвращается обратно в main() к той точке, на которой остановился. Следовательно, следующим стейтментом является вывод строки Ending main() .
Обратите внимание, для вызова функции нужно указать её имя и список параметров в круглых скобках () . В примере, приведенном выше, параметры не используются, поэтому круглые скобки пусты. Мы детально поговорим о параметрах функций на следующем уроке.
Правило: Не забывайте указывать круглые скобки () при вызове функций.
Возвращаемые значения
Когда функция main() завершает свое выполнение, она возвращает целочисленное значение обратно в операционную систему, используя оператор return.
Функции, которые мы пишем, также могут возвращать значения. Для этого нужно указать тип возвращаемого значения (или «тип возврата»). Он указывается при объявлении функции, перед её именем. Обратите внимание, тип возврата не указывает, какое именно значение будет возвращаться. Он указывает только тип этого значения.
Затем, внутри вызываемой функции, мы используем оператор return, чтобы указать возвращаемое значение — какое именно значение будет возвращаться обратно в caller.
Рассмотрим простую функцию, которая возвращает целочисленное значение:
Результат выполнения программы:
Первый вызов функции return7() возвращает 7 обратно в caller, которое затем передается в std::cout для вывода.
Второй вызов функции return7() опять возвращает 7 обратно в caller. Выражение 7 + 3 имеет результат 10 , который затем выводится на экран.
Третий вызов функции return7() опять возвращает 7 обратно в caller. Однако функция main() ничего с ним не делает, поэтому ничего и не происходит (возвращаемое значение игнорируется).
Примечание: Возвращаемые значения не выводятся на экран, если их не передать объекту std::cout. В последнем вызове функции return7() значение не отправляется в std::cout, поэтому ничего и не происходит.
Тип возврата void
Функции могут и не возвращать значения. Чтобы сообщить компилятору, что функция не возвращает значение, нужно использовать тип возврата void. Взглянем еще раз на функцию doPrint() из вышеприведенного примера:
Эта функция имеет тип возврата void, который означает, что функция не возвращает значения. Поскольку значение не возвращается, то и оператор return не требуется.
Вот еще один пример использования функции типа void:
В первом вызове функции returnNothing() выводится Hi! , но ничего не возвращается обратно в caller. Точка выполнения возвращается обратно в функцию main(), где программа продолжает свое выполнение.
Второй вызов функции returnNothing() даже не скомпилируется. Функция returnNothing() имеет тип возврата void, который означает, что эта функция не возвращает значения. Однако функция main() пытается отправить это значение (которое не возвращается) в std::cout для вывода. std::cout не может обработать этот случай, так как значения на вывод не предоставлено. Следовательно, компилятор выдаст ошибку. Вам нужно будет закомментировать эту строку, чтобы компиляция прошла успешно.
Возврат значений функцией main()
Теперь у вас есть понимание того, как работает функция main(). Когда программа выполняется, операционная система делает вызов функции main() и начинается её выполнение. Стейтменты в main() выполняются последовательно. В конце функция main() возвращает целочисленное значение (обычно 0 ) обратно в операционную систему. Поэтому main() объявляется как int main() .
Почему нужно возвращать значения обратно в операционную систему? Дело в том, что возвращаемое значение функции main() является кодом состояния, который сообщает операционной системе об успешном или неудачном выполнении программы. Обычно, возвращаемое значение 0 (ноль) означает что всё прошло успешно, тогда как любое другое значение означает неудачу/ошибку.
Обратите внимание, по стандартам языка C++ функция main() должна возвращать целочисленное значение. Однако, если вы не укажете return в конце функции main(), компилятор возвратит 0 автоматически, если никаких ошибок не будет. Но рекомендуется указывать return в конце функции main() и использовать тип возврата int для функции main().
Еще о возвращаемых значениях
Во-первых, если тип возврата функции не void, то она должна возвращать значение указанного типа (использовать оператор return). Единственно исключение — функция main(), которая возвращает 0 , если не предоставлено другое значение.
Во-вторых, когда процессор встречает в функции оператор return, он немедленно выполняет возврат значения обратно в caller и точка выполнения также переходит в caller. Любой код, который находится за оператором return в функции — игнорируется.
Функция может возвращать только одно значение через return обратно в caller. Это может быть либо число (например, 7 ), либо значение переменной, либо выражение (у которого есть результат), либо определенное значение из набора возможных значений.
Но есть способы обойти правило возврата одного значения, возвращая сразу несколько значений, но об этом детально мы поговорим на соответствующем уроке.
Наконец, автор функции решает, что означает её возвращаемое значение. Некоторые функции используют возвращаемые значения в качестве кодов состояния для указания результата выполнения функции (успешно ли выполнение или нет). Другие функции возвращают определенное значение из набора возможных значений. Кроме того, существуют функции, которые вообще ничего не возвращают.
Повторное использование функций
Одну и ту же функцию можно вызывать несколько раз, даже в разных программах, что очень полезно:
Функции — часть первая
Функция – это блок программного кода на языке JavaScript, который определяется один раз и может выполняться, или вызываться, многократно.
Функция представляет собой именованное объединение группы инструкций. Это объединение может быть вызвано из других частей программы.
Наиболее важной причиной использования функций служит необходимость концептуализировать структуру программы. Деление программы на функции является базовым принципом структурного программирования.
Причиной, из-за которой в свое время была создана концепция функций, стало стремление сократить размер программного кода. Любая последовательность инструкций, встречающаяся в программе более одного раза, будучи вынесенной в отдельную функцию, сокращает размер программы.
Несмотря на то, что функция в процессе выполнения программы исполняется не один раз, ее код хранится только в одной области памяти. На рисунке показано, каким образом функция может вызываться из разных участков программы.
Люди считают, что компьютерные науки – это искусство для гениев. В реальности всё наоборот – просто множество людей делают вещи, которые стоят друг на друге, будто составляя стену из маленьких камушков.
2. Объявление функций
Определение функций выполняется с помощью ключевого слова function, которое может использоваться в выражениях определения функций или в инструкциях объявления функций. В любом случае определение функции начинается с ключевого слова function, за которым указываются следующие компоненты:
— Идентификатор, определяющий имя функции. Имя является обязательной частью инструкции объявления функции;
— Пара круглых скобок вокруг списка из нуля или более идентификаторов, разделенных запятыми. Эти идентификаторы будут определять имена параметров функции и в теле функции могут использоваться как локальные переменные.;
— Пара фигурных скобок с нулем или более инструкций JavaScript внутри. Эти инструкции составляют тело функции: они выполняются при каждом вызове функции.
Обратите внимание на то, что объявление функции не заканчивается точкой с запятой (;).
Объявления говорит интерпретатору о том, функция, имеющая данные атрибуты, будет вызвана позже. Информацию о функции, содержащуюся в ее объявлении также иногда называют сигнатурой функции.
3. Вызов функций
Для того чтобы вызвать функцию, нам понадобились только имя функции и круглые скобки. Вызов функции завершается точкой с запятой (;). Выполнение инструкции вызова функции инициирует выполнение самой функции. Это означает, что управление передается инструкциям функции, которые после своего выполнения, в свою очередь, передают управление инструкции, следующему за вызовом функции. В следующем фрагменте демонстрируется несколько примеров выражений вызова обычных функций.
Вызов функций выполняется с помощью выражения вызова. Выражение вызова состоит из выражения обращения к функции, которое возвращает объект функции, и следующими за ним круглыми скобками со списком из нуля или более выражений-аргументов, разделенных запятыми, внутри.
При вызове функции вычисляются все выражения-аргументы (указанные между скобками), и полученные значения используются в качестве аргументов функции. Эти значения присваиваются параметрам, имена которых перечислены в определении функции. В теле функции выражения обращений к параметрам возвращают значения соответствующих аргументов.
4. Аргументы и параметры функций
Аргументом называют единицу данных (например, переменную), передаваемую в функцию. Аргументы позволяют функции оперировать различными значениями или выполнять различные действия в зависимости от переданных ей значений.
В языке JavaScript, в определениях функций не указываются типы параметров, а при вызове функций не выполняется никаких проверок типов передаваемых значений аргументов. Фактически при вызове функций в языке JavaScript не проверяется даже количество аргументов.
Функцию можно вызвать с любым количеством аргументов. Если параметр не передан при вызове – он считается равным undefined.
4.1 Аргументы по умолчанию
Для указания значения «по умолчанию», то есть, такого, которое используется, если аргумент не указан можно использовать такой приём: проверяем равен ли аргумент undefined, и если получаем true – записываем в него значение по умолчанию.
5. Значение, возвращаемое функцией
Когда выполнение функции завершается, она может возвратить значение программе, которая ее вызвала. Как правило, возвращаемое функцией значение имеет отношение к решению задачи, возложенной на эту функцию. Следующий пример демонстрирует применение функции, получающей значение веса в фунтах и возвращающей эквивалентное значение этого веса в килограммах:
Для возврата значения используется инструкция return. Как только до неё доходит управление – функция завершается. Инструкция return может также использоваться без значения, чтобы прекратить выполнение и выйти из функции. Инструкция return может располагаться только в теле функции. Присутствие ее в любом другом месте является синтаксической ошибкой.
В коде выше, если сработал if, то строка (*) и весь код под ней никогда не выполнится, так как return завершает выполнение функции.
Если функция возвращает значение (а функция в JavaScript всегда возвращает значение), то вызов функции рассматривается как выражение, значение которого равно величине, возвращаемой функцией. Мы можем использовать это выражение аналогично любым другим выражениям; например, мы можем присвоить его значение переменной:
6. Локальные переменные
Функция может содержать локальные переменные, объявленные через var. Такие переменные видны только внутри функции:
Неважно, где именно в функции объявляется переменная. Любое объявление срабатывает один раз и распространяется на всю функцию. Такое поведение var внутри функций называется всплытие, эго мы рассмотрим позже.
7. Внешние переменные
Функция может обратиться ко внешней переменной, например:
Доступ возможен не только на чтение, но и на запись. При этом, так как переменная внешняя, то изменения будут видны и снаружи функции:
Если бы внутри функции, в строке (1), была бы объявлена своя локальная переменная var userName, то все обращения использовали бы её, и внешняя переменная осталась бы неизменной.
Более детально механизм взаимодействия c внешними переменными мы рассмотрим позже.
8. Всплытие внутри функций
Так сложилось, что одна из самых хитрых частей программирования на JavaScript — это локация и способ объявления переменных. В большинстве С-подобных языков переменные (или их связывания) создаются там, где их объявляют. Однако в JavaScript это не совсем так. Используя var объявления, переменная перемещается на начало функции (или в начало глобальной области видимости, если объявление состоялось вне функции) независимо от того, где оно произошло на самом деле — это называется всплытие. Чтобы продемонстрировать это поведение, рассмотрим следующую функцию:
Если вы не знакомы с JavaScript, скорее всего вы ожидаете, что переменная value будет создана только тогда, когда condition будет равняться true. На самом деле value будет создана независимо от этого. Под капотом движок JavaScript изменяет функцию getValue таким образом, что она выглядит так:
Переменная value всплывает вверху блока и в том же месте происходит инициализация. Это означает, что переменная value все еще доступна в блоке else. Однако, если обратиться к ней, получим undefined, потому что она еще не проинициализирована.
Часто новичкам в JavaScript-разработке трудно привыкнуть к тому, как работает объявления переменных, и непонимание этой неочевидной поведения может привести к ошибкам.
9. Именование функций
В качестве имени функции может использоваться любой допустимый идентификатор. Старайтесь выбирать функциям достаточно описательные, но не длинные имена. Искусство сохранения баланса между краткостью и информативностью приходит с опытом. Правильно подобранные имена функций могут существенно повысить удобочитаемость (а значит, и простоту сопровождения) ваших программ.
Чаще всего в качестве имен функций выбираются глаголы или фразы, начинающиеся с глаголов. По общепринятому соглашению имена функций начинаются со строчной буквы. Если имя состоит из нескольких слов, в соответствии с одним из соглашений они отделяются друг от друга символом подчеркивания, примерно так: like_this(), по другому соглашению все слова, кроме первого, начинаются с прописной буквы, примерно так: likeThis(). Имена функций, которые, как предполагается, реализуют внутреннюю, скрытую от посторонних глаз функциональность, иногда начинаются с символа подчеркивания.
— Имя функции должно понятно и чётко отражать, что она делает. Увидев её вызов в коде, вы должны тут же понимать, что она делает.
— Функция – это действие, поэтому для имён функций, как правило, используются глаголы.
10. Резюме
Функция – это блок программного кода на языке JavaScript, который определяется один раз и может выполняться, или вызываться, многократно.
Функции позволяют обеспечить внутреннюю организованность программы и сократить размер ее кода, присваивая повторяющимся фрагментам программы имя и заменяя этим именем все повторения, встречающиеся в программе. Объявление функции задает общий вид функции(сигнатуру) и совокупность действий(тело), выполняемых функцией. Вызов функции передает управление в функцию.
Когда выполнение функции завершается, она может возвратить значение программе, которая ее вызвала. Функция может возвращать только одно значение.
Очень полезно разделять разные задачи, выполняемые программой, на функции. Вам не придётся повторяться, функции делают код более читаемым, разделяя его на смысловые части, так же, как главы и секции книги помогают в организации обычного текста.
Функции являются основными строительными блоками скриптов. Мы будем неоднократно возвращаться к ним и изучать все более и более глубоко.
11. Упражнения
1. Минимум
В предыдущей главе была упомянута функция Math.min, возвращающая самый маленький из аргументов. Теперь мы можем написать такую функцию сами. Напишите функцию min, принимающую два аргумента, и возвращающую минимальный из них.
2. Even number
Создайте функцию isEven, которая возвращает значение true или false в зависимости от того является ли аргумент x четным.
3. dayOfWeek
Создайте функцию, которая принимает в себя число x э [1; 7] и возвращает название дня недели. Используйте switch-case.
4. calcBox
Создайте функцию, которая принимает в себя 3 аргумента и рассчитывает объем коробки.
5. hmsToSecs
Напишите функцию hmsToSecs, имеющую три аргумента h, m, s. Функция должна возвращать эквивалент переданного ей временного значения в секундах. Создайте программу, которая будет циклически запрашивать у пользователя ввод значения часов, минут и секунд и выводить результат работы функции на экран.
6. callCounter
Напишите функцию, которая при каждом вызове будет выводить на экран количество раз, которое она вызывалась ранее. Напишите программу, которая будет вызывать данную функцию не менее 10 раз.
(Задача на использование глобальных переменных)
7. primeNumber
Напишите функцию, которая которая принимает в себя натуральное число n и возвращает самое большое простое число в диапазоне (2; n).