Что означает такое объявление функции
Функции
Определение и объявление функций
Определение функции
Формальное определение функции выглядит следующим образом:
Затем идет имя функции, которое представляет произвольный идентификатор. К именованию функции применяются те же правила, что и к именованию переменных.
После имени функции в скобках идет перечисление параметров. Функция может не иметь параметров, в этом случае указываются пустые скобки.
После заголовка функции в фигурных скобках идет тело функции, которое содержит выполняемые инструкции.
Например, определение функции main, которая должна быть в любой программе на языке C++ и с которой начинается ее выполнение:
Выполнение функции
Для выполнения функции ее необходимо вызвать. Вызов функции осуществляется в форме:
Например, определим и выполним простейшую функцию:
Здесь определена функция hello, которая вызывается в функции main два раза. В этом и заключается преимущество функций: мы можем вынести некоторые общие действия в отдельную функцию и затем вызывать многократно в различных местах программы. В итоге программа два раза выведет строку «hello».
Объявление функции
При использовании функций стоит учитывать, что компилятор должен знать о функции до ее вызова. Поэтому вызов функции должен происходить после ее определения, как в случае выше. В некоторых языках это не имеет значение, но в языке C++ это играет большую роль. И если, к примеру, мы сначала вызовем, а потом определим функцию, то мы получим ошибку на этапе компиляции, как в следующем случае:
В этом случае перед вызовом функции надо ее дополнительно объявить. Объявление функции еще называют прототипом. Формальное объявление выглядит следующим образом:
Фактически это заголовок функции. То есть для функции hello объявление будет выглядеть следующим образом:
Используем объявление функции:
В данном случае несмотря на то, что определение функции идет после ее вызова, но так как функция уже объявлена до ее вызова, то компилятор уже будет знать о функции hello, и никаких проблем в работе программы не возникнет.
Функции
Зачастую нам надо повторять одно и то же действие во многих частях программы.
Например, необходимо красиво вывести сообщение при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.
Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.
Объявление функции
Для создания функций мы можем использовать объявление функции.
Пример объявления функции:
Вызов showMessage() выполняет код функции. Здесь мы увидим сообщение дважды.
Этот пример явно демонстрирует одно из главных предназначений функций: избавление от дублирования кода.
Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.
Локальные переменные
Переменные, объявленные внутри функции, видны только внутри этой функции.
Внешние переменные
У функции есть доступ к внешним переменным, например:
Функция обладает полным доступом к внешним переменным и может изменять их значение.
Внешняя переменная используется, только если внутри функции нет такой локальной.
Переменные, объявленные снаружи всех функций, такие как внешняя переменная userName в вышеприведённом коде – называются глобальными.
Глобальные переменные видимы для любой функции (если только их не перекрывают одноимённые локальные переменные).
Желательно сводить использование глобальных переменных к минимуму. В современном коде обычно мало или совсем нет глобальных переменных. Хотя они иногда полезны для хранения важнейших «общепроектовых» данных.
Параметры
Мы можем передать внутрь функции любую информацию, используя параметры (также называемые аргументами функции).
Параметры по умолчанию
Например, вышеупомянутая функция showMessage(from, text) может быть вызвана с одним аргументом:
Если мы хотим задать параметру text значение по умолчанию, мы должны указать его после = :
Теперь, если параметр text не указан, его значением будет «текст не добавлен»
В данном случае «текст не добавлен» это строка, но на её месте могло бы быть и более сложное выражение, которое бы вычислялось и присваивалось при отсутствии параметра. Например:
В JavaScript параметры по умолчанию вычисляются каждый раз, когда функция вызывается без соответствующего параметра.
Ранние версии JavaScript не поддерживали параметры по умолчанию. Поэтому существуют альтернативные способы, которые могут встречаться в старых скриптах.
Например, явная проверка на undefined :
…Или с помощью оператора || :
Возврат значения
Функция может вернуть результат, который будет передан в вызвавший её код.
Простейшим примером может служить функция сложения двух чисел:
Директива return может находиться в любом месте тела функции. Как только выполнение доходит до этого места, функция останавливается, и значение возвращается в вызвавший её код (присваивается переменной result выше).
Вызовов return может быть несколько, например:
Возможно использовать return и без значения. Это приведёт к немедленному выходу из функции.
Если функция не возвращает значения, это всё равно, как если бы она возвращала undefined :
Пустой return аналогичен return undefined :
Для длинного выражения в return может быть заманчиво разместить его на нескольких отдельных строках, например так:
И тогда всё сработает, как задумано.
Выбор имени функции
Функция – это действие. Поэтому имя функции обычно является глаголом. Оно должно быть простым, точным и описывать действие функции, чтобы программист, который будет читать код, получил верное представление о том, что делает функция.
Как правило, используются глагольные префиксы, обозначающие общий характер действия, после которых следует уточнение. Обычно в командах разработчиков действуют соглашения, касающиеся значений этих префиксов.
Например, функции, начинающиеся с «show» обычно что-то показывают.
Функции, начинающиеся с…
Примеры таких имён:
Благодаря префиксам, при первом взгляде на имя функции становится понятным что делает её код, и какое значение она может возвращать.
Функция должна делать только то, что явно подразумевается её названием. И это должно быть одним действием.
Два независимых действия обычно подразумевают две функции, даже если предполагается, что они будут вызываться вместе (в этом случае мы можем создать третью функцию, которая будет их вызывать).
Несколько примеров, которые нарушают это правило:
В этих примерах использовались общепринятые смыслы префиксов. Конечно, вы в команде можете договориться о других значениях, но обычно они мало отличаются от общепринятых. В любом случае вы и ваша команда должны точно понимать, что значит префикс, что функция с ним может делать, а чего не может.
Имена функций, которые используются очень часто, иногда делают сверхкороткими.
Это исключения. В основном имена функций должны быть в меру краткими и описательными.
Функции == Комментарии
Функции должны быть короткими и делать только что-то одно. Если это что-то большое, имеет смысл разбить функцию на несколько меньших. Иногда следовать этому правилу непросто, но это определённо хорошее правило.
Небольшие функции не только облегчают тестирование и отладку – само существование таких функций выполняет роль хороших комментариев!
Первый вариант использует метку nextPrime :
Второй вариант использует дополнительную функцию isPrime(n) для проверки на простое:
Второй вариант легче для понимания, не правда ли? Вместо куска кода мы видим название действия ( isPrime ). Иногда разработчики называют такой код самодокументируемым.
Таким образом, допустимо создавать функции, даже если мы не планируем повторно использовать их. Такие функции структурируют код и делают его более понятным.
Итого
Объявление функции имеет вид:
Для того, чтобы сделать код более чистым и понятным, рекомендуется использовать локальные переменные и параметры функций, не пользоваться внешними переменными.
Функция, которая получает параметры, работает с ними и затем возвращает результат, гораздо понятнее функции, вызываемой без параметров, но изменяющей внешние переменные, что чревато побочными эффектами.
Функции являются основными строительными блоками скриптов. Мы рассмотрели лишь основы функций в JavaScript, но уже сейчас можем создавать и использовать их. Это только начало пути. Мы будем неоднократно возвращаться к функциям и изучать их всё более и более глубоко.
Задачи
Обязателен ли «else»?
В ином случае она запрашивает подтверждение через confirm и возвращает его результат:
Есть ли хоть одно отличие в поведении этого варианта?
Оба варианта функций работают одинаково, отличий нет.
Перепишите функцию, используя оператор ‘?’ или ‘||’
В ином случае она задаёт вопрос confirm и возвращает его результат.
Сделайте два варианта функции checkAge :
Объявление функции
Объявление функции
Объявление функции определяет ее имя, тип возвращаемого значения, класс памяти и может также задавать тип некоторых или всех аргументов функции. Детальное описание синтаксиса объявлений функции дано в разделе 3.5. В разделе 3.6 рассмотрена зависимость области действия функции от ее класса памяти.
Однако, помимо явного объявления, функция может быть объявлена неявно, по контексту ее вызова. Неявное объявление имеет место всякий раз, когда функция вызывается без предварительного объявления или определения. В этом случае компилятор языка Си считает, что вызываемая функция имеет тип возвращаемого значения int и класс памяти extern. Определение функции, если оно имеется далее в том же самом исходном файле, может переопределить тип возвращаемого значения и класс памяти.
Тип возвращаемого значения функции, указанный в предварительном объявлении, должен соответствовать типу возвращаемого значения в определении функции.
Если функция, тип возвращаемого значения которой не int, вызывается до ее определения или объявления, то компилятор сообщает об ошибке.
Основное назначение предварительного объявления состоит в задании типов и числа аргументов, ожидаемых в вызове функции. Список типов аргументов позволяет компилятору осуществить контроль типов аргументов при вызове функции. Если предварительное объявление отсутствует, то программист сам должен следить за соответствием типов между фактическими аргументами и формальными параметрами. Более детально контроль типов рассмотрен в разделе 6.4.1 «Фактические аргументы».
double realadd (double, double);
double realadd(double x, double y)
В примере функция intadd объявлена неявно с типом возвращаемого значения int, так как она вызнана до своего определения. Компилятор не проверит типы аргументов при вызове функции intadd, поскольку список типов аргументов для нее не задан.
Функция realadd возвращает значение типа double. В функции main имеется предварительное объявление функции realadd. Тип возвращаемого значения (double), заданный в определении, соответствует типу возвращаемого значения, заданному в предварительном объявлении. В предварительном объявлении также определены типы двух параметров функции realadd. Типы фактических аргументов соответствуют типам, заданным в предварительном объявлении, и также соответствуют типам формальных параметров в определении функции realadd.
Читайте также
Объявление переменных
Объявление переменных Перед использованием переменной в коде Web-сценария рекомендуется выполнить ее объявление. Для этого служит оператор объявления переменной var, после которого указывают имя переменной:var x;Теперь объявленной переменной можно присвоить какое-либо
Объявление функций
Объявление функций Прежде чем функция будет использована где-то в Web-сценарии, ее нужно объявить. Функцию объявляют с помощью ключевого слова function:function ([ ]) Имя функции, как уже говорилось, должно
Объявление переменных
Объявление констант
Объявление констант Для объявления констант используется ключевое слово Const: Const cstrPetsName As String = «Пушок» Const cDateTarget Date As Date = #5/26/2000# Const cboolUp As Boolean = True Все вполне аналогично объявлению переменных, за исключением того, что при объявлении константы необходимо указать ее значение.
5.2.9.1. Объявление курсоров
5.2.9.1. Объявление курсоров DECLARE cursor_name CURSOR FOR select_statementЭта инструкция объявляет курсор. Много курсоров может быть объявлено в подпрограмме, но каждый курсор в данном блоке должен иметь уникальное имя.Инструкция SELECT не может иметь предложение
Объявление функции (прототип)
Объявление функции (прототип) Метод объявления функции, описанный в данном разделе, используется только в версии 4.0 СП MSC. В версии 5.0 СП MSC, а также в СП ТС реализован более современный метод — объявление прототипа функции, а старый метод поддерживается в этих версиях лишь
Объявление типа
Объявление типа Существует два особых вида объявления, в которых объявляется не переменная или функция, а тип данных. Первый вид позволяет определить тег и элементы структуры, объединения или перечислимого типа. После такого объявления имя типа (тег) может быть
Объявление тега
Объявление тега Объявление типа структуры, объединения или перечислимого типа имеет такую же синтаксическую форму, как и объявление переменной этих типов, однако в объявлении типа идентификатор переменной (а в общем случае описатель) опущен. Именем типа структуры,
Объявление typedef
Объявление данных
Объявление данных Если непосредственно за ключевым словом near, far или huge следует идентификатор, то это значит, что соответствующий элемент данных будет размещен в стандартном сегменте (для near) или может быть размещен в другом сегменте данных (для far или huge). Например,
Объявление функций
Объявление функций Правила применения модификаторов near и far в объявлениях функций аналогичны правилам применения их в объявлениях данных. Если непосредственно за модификатором следует имя функции, то данное ключевое слово определяет, в каком сегменте будет размещена
Опережающее объявление
Опережающее объявление В некоторых ситуациях возникает необходимость вызвать подпрограмму, описанную далее по тексту программы. Например, такая необходимость возникает при косвенной рекурсии (подпрограмма A вызывает подпрограмму B, а та в свою очередь вызывает
Объявление ссылок
Повторное объявление функции как атрибута
Повторное объявление функции как атрибута
Повторное объявление функции как атрибута Правило Утверждения Переобъявления нуждается в небольшом дополнении ввиду возможности при повторном объявлении задать функцию как атрибут. Что произойдет с предусловием функции и ее постусловием, если таковые имелись?Атрибут
Функции
Функции в JavaScript
Это определяет высокую выразительную мощность JavaScript и позволяет относить его к числу языков, реализующих функциональную парадигму программирования (что само по себе есть очень круто по многим соображениям).
Функция в JavaScript специальный тип объектов, позволяющий формализовать средствами языка определённую логику поведения и обработки данных.
Для понимания работы функций необходимо (и достаточно?) иметь представление о следующих моментах:
Объявление функций
Функции вида «function declaration statement»
Объявление функции (function definition, или function declaration, или function statement) состоит из ключевого слова function и следующих частей:
Например, следующий код объявляет простую функцию с именем square:
Функция square принимает один параметр, названный number. Состоит из одной инструкции, которая означает вернуть параметр этой функции (это number ) умноженный на самого себя. Инструкция return указывает на значение, которые будет возвращено функцией.
Примитивные параметры (например, число) передаются функции значением; значение передаётся в функцию, но если функция меняет значение параметра, это изменение не отразится глобально или после вызова функции.
Если вы передадите объект как параметр (не примитив, например, массив или определяемые пользователем объекты), и функция изменит свойство переданного в неё объекта, это изменение будет видно и вне функции, как показано в следующим примере:
Функции вида «function definition expression»
Функция вида «function declaration statement» по синтаксису является инструкцией (statement), ещё функция может быть вида «function definition expression». Такая функция может быть анонимной (она не имеет имени). Например, функция square может быть вызвана так:
Однако, имя может быть и присвоено для вызова самой себя внутри самой функции и для отладчика (debugger) для идентифицированные функции в стек-треках (stack traces; «trace» — «след» / «отпечаток»).
В следующим коде наша функция принимает функцию, которая является function definition expression, и выполняет его для каждого элемента принятого массива вторым аргументом.
Функция возвращает: [0, 1, 8, 125, 1000].
В JavaScript функция может быть объявлена с условием. Например, следующая функция будет присвоена переменной myFunc только, если num равно 0:
Метод — это функция, которая является свойством объекта. Узнать больше про объекты и методы можно по ссылке: Работа с объектами.
Вызовы функций
Объявление функции не выполняет её. Объявление функции просто называет функцию и указывает, что делать при вызове функции.
Эта инструкция вызывает функцию с аргументом 5. Функция вызывает свои инструкции и возвращает значение 25.
Функции могут быть в области видимости, когда они уже определены, но функции вида «function declaration statment» могут быть подняты (поднятие — hoisting), также как в этом примере:
Область видимости функции — функция, в котором она определена, или целая программа, если она объявлена по уровню выше.
Примечание: Это работает только тогда, когда объявлении функции использует вышеупомянутый синтаксис (т.е. function funcName()<> ). Код ниже не будет работать. Имеется в виду то, что поднятие функции работает только с function declaration и не работает с function expression.
Аргументы функции не ограничиваются строками и числами. Вы можете передавать целые объекты в функцию. Функция show_props() (объявленная в Работа с объектами) является примером функции, принимающей объекты аргументом.
Функция может вызвать саму себя. Например, вот функция рекурсивного вычисления факториала:
Затем вы можете вычислить факториалы от одного до пяти следующим образом:
Область видимости функций
Переменные объявленные в функции не могут быть доступными где-нибудь вне этой функции, поэтому переменные (которые нужны именно для функции) объявляют только в scope функции. При этом функция имеет доступ ко всем переменным и функциям, объявленным внутри её scope. Другими словами функция объявленная в глобальном scope имеет доступ ко всем переменным в глобальном scope. Функция объявленная внутри другой функции ещё имеет доступ и ко всем переменным её родительской функции и другим переменным, к которым эта родительская функция имеет доступ.
Scope и стек функции
Рекурсия
Функция может вызывать саму себя. Три способа такого вызова:
Для примера рассмотрим следующие функцию:
Внутри функции (function body) все следующие вызовы эквивалентны:
Функция, которая вызывает саму себя, называется рекурсивной функцией (recursive function). Получается, что рекурсия аналогична циклу (loop). Оба вызывают некоторый код несколько раз, и оба требуют условия (чтобы избежать бесконечного цикла, вернее бесконечной рекурсии). Например, следующий цикл:
можно было изменить на рекурсивную функцию и вызовом этой функции:
Однако некоторые алгоритмы не могут быть простыми повторяющимися циклами. Например, получение всех элементов структуры дерева (например, DOM) проще всего реализуется использованием рекурсии:
Также возможно превращение некоторых рекурсивных алгоритмов в нерекурсивные, но часто их логика очень сложна, и для этого потребуется использование стека (stack). По факту рекурсия использует stack: function stack.
Поведение стека можно увидеть в следующем примере:
Вложенные функции (nested functions) и замыкания (closures)
Вы можете вложить одну функцию в другую. Вложенная функция (nested function; inner) приватная (private) и она помещена в другую функцию (outer). Так образуется замыкание (closure). Closure — это выражение (обычно функция), которое может иметь свободные переменные вместе со средой, которая связывает эти переменные (что «закрывает» («close») выражение).
Поскольку вложенная функция это closure, это означает, что вложенная функция может «унаследовать» (inherit) аргументы и переменные функции, в которую та вложена. Другими словами, вложенная функция содержит scope внешней («outer») функции.
Следующий пример показывает вложенную функцию:
Поскольку вложенная функция формирует closure, вы можете вызвать внешнюю функцию и указать аргументы для обоих функций (для outer и innner).
Сохранение переменных
Это не отличается от хранения ссылок в других объектах, но часто менее очевидно, потому что не устанавливаются ссылки напрямую и нельзя посмотреть там.
Несколько уровней вложенности функций (Multiply-nested functions)
Функции можно вкладывать несколько раз, т.е. функция (A) хранит в себе функцию (B), которая хранит в себе функцию (C). Обе функции B и C формируют closures, так B имеет доступ к переменным и аргументам A, и C имеет такой же доступ к B. В добавок, поскольку C имеет такой доступ к B, который имеет такой же доступ к A, C ещё имеет такой же доступ к A. Таким образом closures может хранить в себе несколько scope; они рекурсивно хранят scope функций, содержащих его. Это называется chaining (chain — цепь; Почему названо «chaining» будет объяснено позже)
Рассмотрим следующий пример:
Конфликты имён (Name conflicts)
Когда два аргумента или переменных в scope у closure имеют одинаковые имена, происходит конфликт имени (name conflict). Более вложенный (more inner) scope имеет приоритет, так самый вложенный scope имеет наивысший приоритет, и наоборот. Это цепочка областей видимости (scope chain). Самым первым звеном является самый глубокий scope, и наоборот. Рассмотрим следующие:
Замыкания
Closures это один из главных особенностей JavaScript. JavaScript разрешает вложенность функций и предоставляет вложенной функции полный доступ ко всем переменным и функциям, объявленным внутри внешней функции (и другим переменным и функции, к которым имеет доступ эта внешняя функция).
Однако, внешняя функция не имеет доступа к переменным и функциям, объявленным во внутренней функции. Это обеспечивает своего рода инкапсуляцию для переменных внутри вложенной функции.
Также, поскольку вложенная функция имеет доступ к scope внешней функции, переменные и функции, объявленные во внешней функции, будет продолжать существовать и после её выполнения для вложенной функции, если на них и на неё сохранился доступ (имеется ввиду, что переменные, объявленные во внешней функции, сохраняются, только если внутренняя функция обращается к ним).
Closure создаётся, когда вложенная функция как-то стала доступной в неком scope вне внешней функции.
Более сложный пример представлен ниже. Объект с методами для манипуляции вложенной функции внешней функцией можно вернуть (return).
В коде выше переменная name внешней функции доступна для вложенной функции, и нет другого способа доступа к вложенным переменным кроме как через вложенную функцию. Вложенные переменные вложенной функции являются безопасными хранилищами для внешних аргументов и переменных. Они содержат «постоянные» и «инкапсулированные» данные для работы с ними вложенными функциями. Функции даже не должны присваиваться переменной или иметь имя.
Однако есть ряд подводных камней, которые следует учитывать при использовании замыканий. Если закрытая функция определяет переменную с тем же именем, что и имя переменной во внешней области, нет способа снова ссылаться на переменную во внешней области.
Использование объекта arguments
Объект arguments функции является псевдо-массивом. Внутри функции вы можете ссылаться к аргументам следующим образом:
Для примера рассмотрим функцию, которая конкатенирует несколько строк. Единственным формальным аргументом для функции будет строка, которая указывает символы, которые разделяют элементы для конкатенации. Функция определяется следующим образом:
Вы можете передавать любое количество аргументов в эту функцию, и он конкатенирует каждый аргумент в одну строку.
Рассмотрите объект Function в JavaScript-справочнике для большей информации.
Параметры функции
Начиная с ECMAScript 2015 появились два новых вида параметров: параметры по умолчанию (default parameters) и остаточные параметры (rest parameters).
Параметры по умолчанию (Default parameters)
С параметрами по умолчанию проверка наличия значения параметра в теле функции не нужна. Теперь вы можете просто указать значение по умолчанию для параметра b в объявлении функции:
Для более детального рассмотрения ознакомьтесь с параметрами по умолчанию.
Остаточные параметры (Rest parameters)
Остаточные параметры предоставляют нам массив неопределённых аргументов. В примере мы используем остаточные параметры, чтобы собрать аргументы с индексами со 2-го до последнего. Затем мы умножим каждый из них на значение первого аргумента. В этом примере используется стрелочная функция (Arrow functions), о которой будет рассказано в следующей секции.
Стрелочные функции
Более короткие функции
В некоторых функциональных паттернах приветствуется использование более коротких функций. Сравните:
Лексика this
До стрелочных функций каждая новая функция определяла своё значение this (новый объект в случае конструктора, undefined в strict mode, контекстный объект, если функция вызвана как метод объекта, и т.д.). Это оказалось раздражающим с точки зрения объектно-ориентированного стиля программирования.
В ECMAScript 3/5 эта проблема была исправлена путём присвоения значения this переменной, которую можно было бы замкнуть.
В arrow function значением this является окружающий его контекст, так следующий код работает ожидаемо:
Далее
Подробное техническое описание функций в статье справочника Функции
Смотрите также Function в Справочнике JavaScript для получения дополнительной информации по функции как объекту.