Функция — это именованный блок шагов
Когда нужно дать имя какому-то куску логики и переиспользовать его, вы пишете функцию. Самый старый и самый очевидный способ в 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 чаще всего анонимное.