Menu

Объявление функций в JavaScript: синтаксис и hoisting

Разбираемся, как объявлять функции в JavaScript: ключевое слово function, параметры, return, всплытие (hoisting) и когда выбрать declaration, а когда expression.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Функция - это именованный блок шагов

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

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ