Попробуйте себя в топовых IT-профессиях и соберите первое портфолио. Бесплатный курс Попробуйте себя в топовых IT-профессиях и соберите первое портфолио. Бесплатный курс Учиться
Код Справочник по фронтенду
#статьи

Функции в JavaScript: как их объявлять, вызывать и использовать без ошибок

Руководство для тех, кто только начинает изучать JavaScript.

Иллюстрация: Polina Vari для Skillbox Media

Функции — один из самых важных инструментов в JavaScript. С их помощью можно структурировать код, переиспользовать логику и делать программу проще для чтения и поддержки. В этой статье разберём, что такое функции, как их правильно объявлять и вызывать, что такое return, this, замыкания и как избежать типичных ошибок.

Содержание


Зачем вообще нужны функции

Во многих веб-проектах разработчики выполняют одни и те же действия: проверяют формы, открывают модальные окна, управляют выпадающими меню.

Если каждый раз писать один и тот же код, он начинает дублироваться во всём проекте. Когда нужно внести правку, приходится менять все копии. Это долго, и легко ошибиться, а ещё код становится длиннее и сложнее для чтения.

Функции решают эту проблему. С их помощью можно один раз описать нужное поведение, а потом просто вызывать его в нужных местах. Это удобно, сокращает количество строк и делает код чище.

Такой подход помогает:

  • сократить объём кода — не нужно повторять одни и те же фрагменты,
  • улучшить читаемость — можно называть действия своими именами,
  • упростить сопровождение — правки в одном месте срабатывают везде.

Это особенно важно в JavaScript, где многие интерфейсные действия повторяются десятки раз. Без функций код быстро выходит из-под контроля.

Как устроена функция в JavaScript

Функция — это самостоятельный блок кода, который можно вызывать в любом месте программы. Она может принимать входные данные, выполнять действия и возвращать результат.

Пример простой функции:

function sayHello() {
  console.log("Привет!");
}

sayHello();

Здесь:

  • мы объявили функцию sayHello();
  • написали, что она должна делать, — вывести сообщение в консоль;
  • вызвали функцию по имени.

Функция срабатывает, когда мы её вызываем. Если не вызвать, она просто будет существовать в коде без действия.

Формально любая функция в JavaScript проходит три этапа:

  • Объявление — создаём функцию и даём ей имя.
  • Определение поведения — пишем, что именно она должна делать.
  • Вызов — запускаем выполнение по имени с помощью круглых скобок.

Это простой и надёжный способ структурировать код. Вместо того чтобы повторять одно и то же — пишем один раз, вызываем сколько угодно.

Кстати, есть и исключения. Некоторые функции в JavaScript создаются прямо на лету, во время выполнения программ. О них мы расскажем чуть позже.

Как объявить функцию в JavaScript

Чтобы объявить функцию, начните с ключевого слова function, укажите имя, круглые скобки для параметров (даже если их нет), а затем — фигурные скобки с кодом внутри.

function sayHello() {
  console.log("Привет, мир!");
}

Этот код создаёт функцию sayHello, которая содержит внутри себя команду console.log("Привет, мир!").

Способ называется function declaration. Он удобен тем, что функцию можно вызывать ещё до её объявления в коде.

Как вызвать функцию в JavaScript

Создать функцию — только половина дела. Чтобы она сработала, её нужно вызвать. То есть сказать программе: «выполни вот это прямо сейчас».

Для этого пишем имя функции и добавляем круглые скобки:

sayHello();

В этот момент JavaScript находит функцию sayHello и запускает всё, что в ней написано. В нашем примере она выводит в консоль сообщение:

Привет, мир!

Запомните: если функцию не вызвать — она ничего не сделает. Она будет просто ждать своего часа в коде.

Как передавать данные в функцию

Часто бывает нужно, чтобы одна и та же функция работала с разными значениями. Например, вы пишете код для сайта интернет-магазина. Покупателю нужно показать приветствие: «Здравствуйте, [имя]». Имя у каждого пользователя своё, и передать его в функцию гораздо удобнее, чем писать для каждого посетителя свой блок кода.

Для этого в функцию можно передавать данные. При её создании мы указываем параметры — это пустые места, в которые потом подставятся нужные значения. А при вызове передаём конкретные данные, которые функция и использует.

function sayHelloName(name) {
  console.log("Привет, " + name + "!");
}

sayHelloName("Андрей"); // "Привет, Андрей!"
sayHelloName("Марина"); // "Привет, Марина!"

Здесь name — это параметр функции sayHelloName. При вызове функции мы передаём конкретное значение, которое подставляется вместо name.​

Добавление нескольких параметров

Можно передавать сразу несколько параметров. Указываем их через запятую:

function sayHelloFullname(name, surname) {
  console.log("Привет, " + name + " " + surname + "!");
}

sayHelloFullname("Андрей", "Иванов"); // "Привет, Андрей Иванов!"

Определение параметра по умолчанию

Не всегда получается передать все значения во время вызова функции. В таких случаях можно задать значение по умолчанию, тогда JavaScript сам подставит нужное значение.

function sayHelloName(name = "гость") {
  console.log("Привет, " + name + "!");
}

sayHelloName(); // "Привет, гость!"
sayHelloName("Катя"); // "Привет, Катя!"

Здесь, если функция sayHelloName вызывается без аргумента, параметр name принимает значение "гость".​

Значения по умолчанию могут быть не только строками или числами. Это может быть результат выражения или вызова другой функции. Можно, допустим, установить текущую дату и время в качестве значения по умолчанию.

function logEvent(message, timestamp = new Date().toISOString()) {
    console.log(`[${timestamp}] ${message}`);
}

logEvent("Неверный логин"); 
// [2025-02-22T12:34:56.789Z] Неверный логин

logEvent("Ошибка подключения", "2025-01-01T00:00:00Z");
// [2025-01-01T00:00:00Z] Ошибка подключения

Неизвестное количество параметров у функции

Иногда заранее не известно, сколько параметров передастся в функцию. Например, пользователь может выбрать один, два или десять элементов из списка — и все они должны попасть в функцию. В этом случае пригодится оператор ... (rest), который собирает все дополнительные аргументы в массив. Он записывается в виде трёх точек перед нужным параметром.

function sayHelloManynames(...names) {;
let fullName = names.join(" "); 
console.log(`Привет, ${fullName}!`); // Объединяет все имена в одну строку с пробелами
}

sayHelloManynames("Омар", "ибн", "аль-Хаттаб", "аль-Фарук"); 
// Привет, Омар абн аль-Хаттаб аль-Фарук!

Здесь ...names собирает все переданные аргументы в массив names, который затем объединяется в строку с помощью join(" ").

Как вернуть результат из функции: оператор return

Функции в JavaScript могут не только выполнять действия, но и возвращать результат своей работы. Допустим, вы пишете калькулятор. Пользователь вводит два числа, а калькулятору нужно показать сумму. В этом случае удобно создать функцию sum(a, b), которая возвращает результат сложения. Вы передаёте ей значения и получаете ответ, с которым можно работать дальше — например, отобразить его на экране или использовать в других вычислениях.

Для этого используется ключевое слово return. Оператор позволяет функции вернуть значение в то место, из которого она была вызвана. Это полезно, когда необходимо использовать результат вычислений функции в других частях программы.

function greet(name) {
    return "Привет, " + name + "!";
  }

  const message = greet("Марина");
  console.log(message); //Выведет: "Привет, Марина!"

Здесь:

  • JavaScript выполнит вызов функции greet(), передав ей строку "Марина";
  • вернёт полученную строку "Привет, Марина!" и присвоит её переменной message;
  • выведет message на печать.

Важно: когда интерпретатор JavaScript встречает return, выполнение функции немедленно прекращается. Код после return внутри функции не будет выполнен.​

function greet(name) {
  return "Привет, " + name + "!";
  console.log("Это сообщение никогда не будет выведено.");
}

Что можно вернуть из функции

Функция может возвращать любое значение:

  • строку или число;
  • массив;
  • объект;
  • другую функцию.
function createUser(name, age) {
    return {
        name: name,
        age: age
    };
}

console.log(createUser("Тимофей", 25));
// { name: "Тимофей", age: 25 }

Возврат значений часто используется, чтобы создавать структуру данных — например, карточку пользователя, заказ или товар.

Функции без return

Бывают случаи, когда от функции не нужно никакого результата. Она просто что-то делает — например, выводит сообщение, запускает анимацию или меняет содержимое страницы.

В таких функциях можно не использовать return. Они сработают, выполнят действия, и всё.

function greet(name) {
  console.log("Привет, " + name + "!");
}

const message = greet("Марина"); // Выведет: «Привет, Марина!»
console.log(message); // Выведет: undefined

Что произойдёт:

  • в консоль выведется "Привет, Марина!";
  • затем выведется undefined, потому что функция greet() ничего не вернула.

Если в функции нет return, JavaScript автоматически возвращает undefined.

Чем отличается функция, возвращающая значение, от функции без return:

  • Если функция использует return, она возвращает указанное значение.
  • Если функция не использует return, она по умолчанию возвращает undefined.

Области видимости в функциях JS: глобальная и локальная

В JavaScript область видимости (scope) — это правило, по которому переменные доступны в разных частях кода. Когда мы объявляем переменную, она «живёт» только в определённой зоне. И важно понимать, где именно она будет доступна.

С функциями связаны две основные области видимости: глобальная и локальная.

Глобальная область

Если переменная создана вне функции, она глобальная. Такая переменная доступна в любом месте программы, в том числе внутри функций.

const globalVar = "Я доступна везде!"; // Глобальная переменная

function showVar() {
    console.log(globalVar); // Доступ к глобальной переменной внутри функции
}

showVar(); // «Я доступна везде!»

Важно: глобальные переменные легко случайно изменить из разных частей программы. Это может привести к ошибкам, которые трудно отследить.

Локальная область

Если переменная объявлена внутри функции, она локальная. То есть доступна только в этой функции и нигде больше.

function showVar() {
let localVar = «Я доступна в функции!»;
console.log(localVar); // Доступна внутри функции
}

showVar(); // «Я доступна в функции!»
console.log(localVar); // Ошибка! localVar не определена за пределами функции

Почему так: переменная localVar существует только внутри функции showVar. За её пределами она не видна и не может быть использована.

Важно: локальные переменные защищены от изменений извне. Это делает код более предсказуемым и безопасным.

Замыкание в JS: наследование областей видимости

В JavaScript функция может «запоминать» переменные из того места, где она была создана. Даже если вызвать её позже, в другом месте, — она всё равно будет помнить эти значения.

Когда одна функция создаётся внутри другой, внутренняя функция сохраняет доступ ко всем переменным, которые были в момент её создания. Даже если внешняя функция уже завершила работу, эти переменные остаются доступны.

Представьте, что внутренняя функция как будто кладёт переменные в невидимый «рюкзак» и носит с собой:

function createCounter() {
    let count = 0; // Переменная из внешней области видимости
 
    return function() {  
      count++;
      console.log("Текущее значение:", count);
    }; // Внутренняя функция, имеющая доступ к count
  }
 
  const counter = createCounter(); // Создаём функцию-счётчик
 
  counter(); // Текущее значение: 1
  counter(); // Текущее значение: 2
  counter(); // Текущее значение: 3

Здесь:

  • createCounter() создаёт переменную count и возвращает функцию;
  • эта функция увеличивает count и выводит его значение;
  • даже после завершения createCounter() переменная count не исчезает, — она «живёт» внутри замыкания.

Это и есть замыкание: внутренняя функция «помнит» переменную count, потому что была создана в той же области видимости.

Замыкания удобны, когда нужно, чтобы функция помнила информацию между вызовами. Это может быть полезно в разных ситуациях:

  • вы создаёте счётчик, который увеличивается каждый раз, когда вызывается функция;
  • пишете обработчик событий, которому нужно помнить, что было раньше;
  • хотите сгенерировать уникальные ID и не повторяться;
  • хотите спрятать данные от внешнего доступа и не дать другим частям программы их менять.

Во всех этих случаях замыкание помогает сохранить переменные внутри функции, не делая их глобальными.

Объявление функции через function expression

В JavaScript есть два основных способа создать функцию:

  • через function declaration — привычное объявление с ключевым словом function;
  • Через function expression — функция создаётся внутри выражения и сохраняется в переменную.

Пример:

const greet = function () {
  console.log("Привет!");
};

greet();

Такую функцию нельзя вызвать до её создания, потому что переменная, в которую она записана, появляется только в момент выполнения.

Когда это бывает полезно

Допустим, у нас есть условие: если пользователю меньше 18 — одно сообщение, если больше — другое. Мы хотим выбрать подходящую функцию в зависимости от возраста.

const age = Number(prompt("Сколько вам лет?")); // Выводит диалоговое окно с вопросом
let greet; // Объявляем переменную greet, которой затем присвоим значение функции

if (age < 18) {
  greet = function() {
    alert("Привет!");
  };
} else {
  greet = function() {
    alert("Здравствуйте!");
  };
}

greet();

Здесь:

  • мы запрашиваем возраст с помощью prompt();
  • определяем функцию greet() в зависимости от значения age;
  • вызываем greet(), и пользователь получает соответствующее приветствие.

Важно: пример с prompt() и alert() работает только в браузере. В среде Node.js такие функции не поддерживаются.

Почему не стоит использовать function declaration внутри if

Если попробовать создать функцию обычным способом — function greet() { ... } — прямо внутри if, могут возникнуть проблемы.

В JS есть директива use strict, которая включает строгий режим. Он делает код более безопасным: запрещает некоторые устаревшие конструкции и помогает сразу замечать ошибки.

В строгом режиме такая функция будет существовать только внутри блока if. За пределами блока она будет недоступна — и, если вы попытаетесь её вызвать снаружи, получите ошибку.

Function expression — это способ избежать этой ошибки. Мы сначала создаём переменную, например greet, а потом в нужный момент записываем в неё нужную функцию. Так код работает надёжно и предсказуемо — вне зависимости от условий.

Стрелочные функции (arrow functions) в JavaScript

Стрелочные функции — это короткий способ записать функцию. Их добавили в JavaScript в 2015 году (ES6).

Главное отличие — вместо function используется стрелка =>. Ещё одна особенность: если внутри функции всего одна строка, можно не писать фигурные скобки и return — JavaScript поймёт всё сам.

Пример:

const greet = (name) => `Привет, ${name}!`;
console.log(greet("Анна")); // Выведет: «Привет, Анна!»

Почему это удобно:

  • Меньше кода. Особенно для коротких функций, которые делают что-то одно.
  • Проще читать. Нет function, нет лишних скобок, — всё ясно с первого взгляда.
  • this работает иначе. В стрелочных функциях this не меняется. Это удобно, когда нужно сохранить контекст из внешней области.

This: как работает контекст выполнения в функциях JavaScript

Когда JavaScript начинает выполнять код, он создаёт для этого специальную «рабочую зону». Эта зона называется контекстом выполнения (или просто контекстом). Она помогает понять, где сейчас выполняется код и какие переменные и объекты доступны.

У каждого контекста есть три важные части:

  • Область видимости — показывает, какие переменные и функции доступны в данный момент.
  • this — указывает на объект, к которому привязана текущая функция.
  • Стек вызовов (call stack) — как стопка тарелок: JavaScript складывает туда функции, когда они вызываются, и убирает обратно, когда они завершаются.

Виды контекста в JS: глобальный, функциональный и this

1. Глобальный контекст. Когда страница загружается (или скрипт запускается), создаётся глобальный контекст. В браузере это объект window, в Node.js — global.Все переменные и функции, созданные вне других блоков, становятся частью этого объекта.

console.log(this); // В браузере: window

2. Контекст функции. Каждый раз, когда вызывается функция, создаётся новый контекст. Внутри него есть свои переменные, аргументы и значение this.

function greet() {
    console.log(this); // В обычной функции this зависит от способа вызова
}
greet();

Если вызвать greet() просто так, this укажет на window (в нестрогом режиме).

3. Контекст объекта (this). Когда функция вызывается как метод объекта, this ссылается на этот объект.

const user = {
  name: "Андрей",
  greet() {
    console.log(`Привет, ${this.name}`);
  }
};

user.greet(); // Привет, Андрей

Здесь this ссылается на объект user, поэтому мы получаем имя пользователя.

Есть и другие контексты: у конструкторов, стрелочных функций и обработчиков событий. У каждого есть особенности, о которых мы расскажем в разделах справочника, посвящённых этим темам.

Стек вызовов: очерёдность выполнения кода

Когда JavaScript вызывает функцию, он кладёт её в стек вызовов — список, в котором отслеживается порядок выполнения. Это работает по принципу LIFO (last in, first out): последним пришёл, первым ушёл.

Рассмотрим на примере двух вложенных функций.

function first() { 
  second(); }

function second() {
  console.log("Привет из второй функции!");
} 

first();

Как меняется стек вызовов поэтапно:

  • JavaScript начинает выполнение — стек пуст.
  • Вызов first(). Функция first() добавляется в стек.
  • Внутри first() вызывается second(). second() добавляется в стек поверх first().
  • second() выполняет console.log. Вызов console.log() попадает в стек.
  • console.log() завершился. После вывода в консоль, console.log() убирается из стека.
  • second() завершилась, — она убирается из стека.
  • first() завершилась, стек пуст.

Типичные ошибки при работе с функциями в JavaScript: как их избежать

Одна из распространённых ошибок при работе с функциями — забыть или неправильно использовать return.

return на новой строке без ()

function getNumber() {
    return 
    42; // return завершает выполнение, и эта строка не выполнится!
}

console.log(getNumber()); // undefined

Почему так происходит: JavaScript думает, что return уже завершил функцию. А 42 он просто игнорирует.

Правильный вариант:

function getNumber() {
    return 42; // Возвращаем число правильно
}

Если всё же хочется перенести число на новую строку, оберните его скобками:

function getNumber() {
    return (
        42
    );
}

console.log(getNumber()); // 42

Нет return в некоторых ветках кода

function checkAge(age) {
    if (age >= 18) {
        return "Доступ разрешён";
    }
    // Здесь нет return!
}

console.log(checkAge(20)); // "Доступ разрешён"
console.log(checkAge(15)); // undefined (ожидали строку, но её нет)

Почему так: если age < 18, функция ничего не возвращает, и результат undefined.

Правильный вариант:

function checkAge(age) {
    if (age >= 18) {
        return "Доступ разрешён";
    }
    return "Доступ запрещён"; // Теперь всегда есть return
}

console.log(checkAge(15)); // «Доступ запрещён»

Рекурсивная функция без выхода

function countdown(n) {
    console.log(n);
    countdown(n - 1); // Функция вызывает саму себя без остановки!
}

countdown(5);

Что произойдёт:

  • Функция countdown будет бесконечно уменьшать n.
  • Когда n станет отрицательным, вызовы продолжатся.
  • В итоге JavaScript выдаст «Maximum call stack size exceeded» (переполнение стека).

Чтобы всё исправить, надо добавить условие выхода.

Правильный вариант:

function countdown(n) {
    if (n <= 0) { // Условие выхода
        console.log("Стоп!");
        return;
    }
    
    console.log(n);
    countdown(n - 1); 
}

countdown(5); // Выдаст 5 ... 4 ... 3 ... 2 ... 1 и остановится

null вместо undefined при значении по умолчанию

function greet(name = "Гость") {
    console.log(`Привет, ${name}!`);
}

greet(null); // "Привет, null!"

Почему так: в функции задано значение по умолчанию ("Гость"), и мы хотим его использовать. Значения по умолчанию срабатывают, только если аргумент не определён (undefined). В JavaScript null и undefined часто используются как «отсутствие значения», но они не идентичны. Иногда разработчики явно задают null, думая, что это undefined.

Правильный вариант:

function greet(name = "Гость") {
    console.log(`Привет, ${name}!`);
}

greet(); // "Привет, Гость!"
greet(undefined); // "Привет, Гость!"

Советы и лайфхаки для работы с функциями в JavaScript

Используйте понятные имена.

  • Давайте функциям ясные и осмысленные названия, чтобы код было легче читать и понимать.
  • Вместо неопределённого ct лучше использовать calculateTotal.

Пишите короткие и лаконичные функции.

  • Одна функция должна выполнять одну конкретную задачу.
  • Если код слишком разрастается, разбейте его на несколько функций.

Используйте const и let вместо var.

  • const для неизменяемых переменных, let для изменяемых.
  • Это улучшает читаемость и снижает вероятность ошибок.

Не изменяйте переданные аргументы.

  • Функция не должна менять входные данные, если это не её основная цель.
  • При необходимости возвращайте новый результат.

Используйте параметры по умолчанию.

  • Позволяет избежать ошибок, если аргумент не передан.

Практика: тренируемся в использовании функций в JavaScript


Упражнение 1: сумма чисел, кратных 3

Напишите функцию, которая принимает массив целых чисел и возвращает сумму всех чисел, кратных 3.

Решение:

function sumMultipleOfThree(arr) { 
let sum = 0; 
for (let i = 0; i < arr.length; i++) { 
if (arr[i] % 3 === 0) { 
sum += arr[i]; 
} 
} 
return sum; 
}

Упражнение 2: проверка на палиндром

Напишите функцию, которая определяет, является ли переданная строка палиндромом. Палиндромом считается строка, которая читается одинаково как слева направо, так и справа налево.

Решение:

function isPalindrome(str) {
  const reversedStr = str.split('').reverse().join('');
  return str === reversedStr;
}
// Примеры использования:
console.log(isPalindrome('level')); ``// Вернёт true
console.log(isPalindrome('hello')); ``// Вернёт false

Здесь:

  • str.split('') — превращает строку в массив символов (например, 'hello' → ['h', 'e', 'l', 'l', 'o'])
  • reverse() — переворачивает массив ( ['h', 'e', 'l', 'l', 'o'] → ['o', 'l', 'l', 'e', 'h'])
  • join('') — собирает массив обратно в строку ( ['o', 'l', 'l', 'e', 'h'] → 'olleh')

Сравниваем оригинал и перевёрнутую строку:
return str === reversedStr;

Упражнение 3. Генератор случайных сообщений

Напишите функцию, которая возвращает случайное сообщение из заранее заданного списка.

Список сообщений:

  • «Ты молодец!»
  • «Продолжай в том же духе!
  • «Отличная работа!»
  • «Ты на верном пути!»

Решение:

function generateRandomMessage() {
  const messages = [
    "Ты молодец!",
    "Продолжай в том же духе!",
    "Отличная работа!",
    "Ты на верном пути!"
  ];
  const index = Math.floor(Math.random() * messages.length); // Выбор случайного индекса из массива
  return messages[index]; // Возврат выбранного сообщения
}

console.log(generateRandomMessage());

Здесь:

  • Math.random() → генерирует случайное число от 0 до 1 (например, 0.72).
  • Умножаем это число на messages.length (количество элементов в заданном списке, в данном случае 4).
  • Math.floor(...) округляет вниз до целого числа от 0 до 3 — это и есть случайный индекс массива.
  • return messages[index] — возвращается сообщение, определённое по индексу.

Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!




Изучайте IT на практике — бесплатно

Курсы за 2990 0 р.

Я не знаю, с чего начать
Научитесь: Профессия Фронтенд-разработчик Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована