Функция - это именованный блок шагов
Когда нужно дать имя какому-то куску логики и переиспользовать его, вы пишете функцию. Самый старый и самый очевидный способ в JavaScript - это function declaration (объявление функции): ключевое слово function, а за ним имя.
Читаем слева направо:
function- ключевое слово, с которого начинается объявление функции.greet- имя функции.(name)- список параметров, то есть входные данные функции.- Блок в фигурных скобках - тело функции.
greet("Ada")- это вызов. JavaScript выполняет тело, подставив вnameзначение"Ada".
Само по себе объявление функции её не запускает. Запускает - вызов.
Параметры и аргументы
Параметр - это имя, указанное в определении функции. Аргумент - конкретное значение, которое вы передаёте при вызове. В обиходе эти слова используют как синонимы, но разница становится важна, когда начинаешь разбирать сообщения об ошибках.
Здесь base и exponent - это параметры, а 2 и 10 - аргументы. JavaScript связывает их по порядку: первый аргумент уходит в первый параметр, второй - во второй, и так далее.
В отличие от некоторых других языков, JavaScript не будет ругаться, если вы передадите не столько аргументов, сколько ожидается. Недостающие станут undefined, а лишние просто молча проигнорируются. С одной стороны, это гибко, с другой - иногда подставляет подножку. К значениям по умолчанию и rest-параметрам мы ещё вернёмся в следующих разделах.
return: возвращаем значение из функции
console.log просто печатает что-то в консоль. А вот return в javascript передаёт значение обратно тому, кто вызвал функцию, чтобы его можно было дальше использовать:
Без return функция вернёт undefined:
return также моментально завершает работу функции. Ранний выход через return - это стандартный приём, позволяющий отсечь крайние случаи до основной логики:
Ранний возврат (early return) спасает основное тело функции от превращения в «лесенку» из if/else.
Hoisting функций в JavaScript: вызываем раньше, чем объявили
Вот момент, который реально ставит в тупик тех, кто пришёл из других языков. Объявления функций (function declaration) подвергаются всплытию (hoisting) - JavaScript как бы поднимает их в начало области видимости ещё до того, как начнёт выполнять код. То есть функцию спокойно можно вызвать строкой выше, чем она объявлена:
Этот код отработает без ошибок. Перед выполнением движок сканирует область видимости, регистрирует square как функцию, и только потом начинает построчно выполнять инструкции.
Это реальное различие в поведении между function declaration и остальными способами создать функцию (function expression, стрелочные функции). Последние всплывают как переменные - имя уже известно, но значение присваивается только тогда, когда исполнение дойдёт до нужной строки. Подробнее об этом - дальше.
Большинство стайл-гайдов всё равно советуют объявлять функции до того, как вы их вызываете. Hoisting - это подстраховка, а не приём, на который стоит опираться.
Разница между function declaration и function expression
Function declaration - это самостоятельная инструкция. Function expression появляется там, где ожидается значение - чаще всего после знака присваивания:
И объявление, и выражение дают вам вызываемую функцию. Но отличия всё же есть:
- Function declaration всплывает целиком (полный hoisting). А function expression подчиняется правилам всплытия той переменной, которой она присвоена:
constиletдо момента выполнения строки находятся во временной мёртвой зоне (TDZ). - У declaration обязательно должно быть имя. Expression может быть анонимной, хотя именованная функция даёт более понятный стек вызовов при отладке.
- Declaration нельзя писать где попало. В strict mode конструкция вида
function foo() {}внутри блокаifведёт себя по-разному в разных движках - в таких местах лучше использовать expression.
Для большинства вспомогательных функций верхнего уровня в файле declaration смотрится естественнее. А вот когда функцию передают аргументом или присваивают свойству объекта, обычно берут function expression (или стрелочную функцию).
Имена и стиль оформления
Имя функции - это обещание того, что она делает. Несколько лишних символов на понятное, говорящее имя окупаются в первый же раз, когда код будет читать другой человек (или вы сами через полгода).
Пара соглашений, которых стоит придерживаться:
- Имена функций - это глаголы:
fetchProfile,computeTotal,sendEmail. - Пишем в
camelCase- это норма в JavaScript. - Функции, возвращающие булево значение, часто начинаются с
is,hasилиcan:isValid,hasAccess,canEdit.
Суть в том, чтобы вызов функции читался как обычное предложение.
Небольшой рабочий пример
Соберём всё вместе - параметры, ранний return и говорящее имя:
Одно объявление, ранний выход через guard clause, понятный return. Этой схемы хватит для большинства функций, которые вы будете писать.
Дальше: стрелочные функции
Function declaration - рабочая лошадка, но современный JavaScript всё чаще тяготеет к более краткому синтаксису - стрелочным функциям. Особенно это заметно в колбэках и однострочниках. Выглядят они иначе, ведут себя иначе в отношении this - как раз об этом следующая страница.
Часто задаваемые вопросы
Как объявить функцию в JavaScript?
Пишем ключевое слово function, затем имя, круглые скобки с параметрами и тело в фигурных скобках. Например: function greet(name) { return 'Привет, ' + name; }. Вызывается такая функция по имени со скобками: greet('Ada').
Что такое hoisting (всплытие) функций в JavaScript?
Объявления функций поднимаются наверх своей области видимости ещё до выполнения кода - поэтому вызвать функцию можно даже выше той строки, где она написана. Но работает это только для function-объявлений: функциональные выражения и стрелочные функции, присвоенные let или const, так не всплывают.
В чём разница между function declaration и function expression?
Declaration - это самостоятельная инструкция (function greet() {}), и она всплывает. Expression - это присваивание функции переменной (const greet = function() {}), и тут действуют обычные правила hoisting для переменных. При этом declaration всегда имеет имя, а expression чаще всего анонимное.