$ sudo teach IT
РАЗДЕЛ 6 · УРОК 1

Объявление функций и return

Функция — это один из самых главных строительных блоков в программировании. Здесь разберём: зачем они вообще нужны, как их объявлять двумя способами, что такое return и почему без него функция возвращает undefined.

⏱ ~25 минут 🎓 Для новичков 🟡 JavaScript

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

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

// Площадь прямоугольника 1
let width1 = 5;
let height1 = 3;
let area1 = width1 * height1;
console.log("Площадь 1:", area1);

// Площадь прямоугольника 2
let width2 = 10;
let height2 = 4;
let area2 = width2 * height2;
console.log("Площадь 2:", area2);

// Площадь прямоугольника 3
let width3 = 7;
let height3 = 2;
let area3 = width3 * height3;
console.log("Площадь 3:", area3);

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

💡 Принцип DRY (Don't Repeat Yourself — «не повторяйся»): каждый кусок логики должен жить в одном месте. Функции — главный инструмент соблюдения этого принципа.

Функции решают две ключевые проблемы:

♻️
Переиспользование

Написал один раз — вызываешь сколько угодно раз. Изменил в одном месте — изменилось везде.

🧩
Декомпозиция

Разбиваешь большую задачу на маленькие понятные части. Каждая функция делает одну конкретную вещь.

📖
Читаемость

Вызов calculateArea(5, 3) читается как книга. Не нужно разбираться в деталях реализации каждый раз.

📝 Способ 1: Function Declaration (объявление функции)

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

function имяФункции(параметры) {
  // тело функции — код, который выполнится при вызове
}

Реальный пример — функция приветствия:

// Объявление функции
function greet(name) {
  console.log("Привет, " + name + "!");
}

// Вызов функции — просто пишем имя и скобки
greet("Иван");   // Привет, Иван!
greet("Мария");  // Привет, Мария!
greet("Алекс");  // Привет, Алекс!

Разберём каждую часть по отдельности:

  • function — ключевое слово, говорит JavaScript: «дальше идёт функция»
  • greet — имя функции. Называй глаголом или глагол+существительное: greet, calculateArea, sendEmail
  • (name) — параметр: переменная, которая получит значение при вызове. Может быть несколько через запятую
  • { ... } — тело функции: код, который выполнится каждый раз при вызове
  • greet("Иван") — вызов функции. В скобках — аргумент, значение которое подставится в name

Ещё пример — функция с несколькими параметрами, вычисляющая площадь прямоугольника:

function calculateArea(width, height) {
  let area = width * height;
  console.log("Площадь:", area);
}

calculateArea(5, 3);   // Площадь: 15
calculateArea(10, 4);  // Площадь: 40
calculateArea(7, 2);   // Площадь: 14

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

📌 Способ 2: Function Expression (функциональное выражение)

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

// Function Expression — функция как значение переменной
const greet = function(name) {
  console.log("Привет, " + name + "!");
};

// Вызов — такой же, через имя переменной и скобки
greet("Иван");   // Привет, Иван!
greet("Мария");  // Привет, Мария!

👀 Обратите внимание: после закрывающей фигурной скобки стоит точка с запятой ;. Это потому что мы присваиваем значение переменной, а присваивание — это выражение, которое заканчивается точкой с запятой.

Главная практическая разница между двумя способами — в hoisting (поднятии). Об этом подробно поговорим в уроке 6.5. Пока запомните основное:

Function Declaration ✅

Можно вызвать до объявления в коде. JavaScript «поднимает» её наверх файла автоматически.

greet("Иван"); // Работает!
function greet(name) {
  console.log("Привет, " + name);
}
Function Expression ❌

Нельзя вызвать до строки с присваиванием. Переменная ещё не имеет значения.

greet("Иван"); // Ошибка!
const greet = function(name) {
  console.log("Привет, " + name);
};

На практике оба способа широко используются. Function declaration — чаще для именованных «рабочих» функций программы. Function expression — чаще когда функцию нужно передать как аргумент или сохранить в объект.

↩️ Ключевое слово return

Пока наши функции только выводили текст через console.log. Но функции могут возвращать значение — то есть производить результат, который можно сохранить в переменную или использовать дальше.

Ключевое слово return делает именно это: возвращает значение из функции наружу — туда, где функция была вызвана.

// Функция БЕЗ return — только выводит
function showArea(width, height) {
  console.log(width * height); // просто печатает
}

// Функция С return — возвращает значение
function calculateArea(width, height) {
  return width * height; // возвращает число
}

// Разница при использовании:
showArea(5, 3);           // Выведет 15, но нельзя сохранить
let area = calculateArea(5, 3); // area = 15, можно использовать дальше!

console.log(area);              // 15
console.log(area * 2);          // 30 — используем результат в вычислениях
console.log("Площадь: " + area + " кв.м"); // "Площадь: 15 кв.м"

💡 Правило большого пальца: Если функция что-то вычисляет — используй return. Если функция что-то делает (отправляет email, рисует на экране) — return часто не нужен.

Ещё пример с функцией проверки на чётность:

function isEven(number) {
  return number % 2 === 0; // возвращает true или false
}

console.log(isEven(4));   // true
console.log(isEven(7));   // false

// Результат можно использовать в условии:
if (isEven(10)) {
  console.log("Число чётное!");
}

🚪 Ранний return — выход из функции

return делает две вещи одновременно: возвращает значение и немедленно завершает функцию. Код после return никогда не выполнится.

Это очень полезно для «раннего выхода» — когда мы хотим прекратить выполнение функции при определённом условии:

function divide(a, b) {
  if (b === 0) {
    return "Ошибка: деление на ноль!"; // ранний return — выходим сразу
  }
  // Эта строка выполнится только если b !== 0
  return a / b;
}

console.log(divide(10, 2));  // 5
console.log(divide(10, 0));  // "Ошибка: деление на ноль!"

Без раннего return код был бы сложнее читать — пришлось бы вкладывать логику в else-блоки. Ранний return делает функции чище и понятнее.

// Без раннего return (хуже — глубокая вложенность)
function divide(a, b) {
  if (b !== 0) {
    return a / b;
  } else {
    return "Ошибка: деление на ноль!";
  }
}

// С ранним return (лучше — плоский код)
function divide(a, b) {
  if (b === 0) return "Ошибка: деление на ноль!";
  return a / b;
}

🔑 return без значения (просто return;) тоже завершает функцию — но возвращает undefined. Это используется для раннего выхода из функций, которые ничего не возвращают.

❓ Функция без return возвращает undefined

Важный момент: любая функция в JavaScript что-то возвращает. Если вы не написали return — функция автоматически возвращает специальное значение undefined.

function sayHello() {
  console.log("Привет!"); // функция что-то делает, но ничего не возвращает
}

let result = sayHello(); // Привет! — выведет в консоль
console.log(result);     // undefined — функция вернула undefined

// Это может быть источником ошибок:
function double(n) {
  let result = n * 2;
  // Забыли написать return!
  // return result; // <-- нужна эта строка
}

let x = double(5);
console.log(x);  // undefined (не 10!)
console.log(x + 1); // NaN — потому что undefined + 1 = NaN

⚠️ Частая ошибка новичков: написать вычисление внутри функции, но забыть return. Функция посчитает всё правильно внутри, но результат «испарится» и наружу выйдет undefined.

Запомните: вызвать функцию и получить её значение — разные вещи:

function calculateArea(w, h) {
  return w * h;
}

// "Вызвать функцию" — запустить код внутри
calculateArea(5, 3); // выполнилась, посчитала 15, но результат нигде не сохранён

// "Вернуть значение" — получить результат наружу
let area = calculateArea(5, 3); // теперь area = 15

// Или использовать прямо в выражении:
console.log(calculateArea(5, 3) * 2); // 30

🛠️ Полный пример: собираем всё вместе

Давайте напишем небольшую программу с несколькими функциями — расчёт стоимости заказа. Здесь будет и return, и ранний return, и использование результата одной функции в другой.

// Функция расчёта цены со скидкой
function applyDiscount(price, discountPercent) {
  if (discountPercent < 0 || discountPercent > 100) {
    return "Ошибка: некорректная скидка";
  }
  let discount = price * discountPercent / 100;
  return price - discount;
}

// Функция расчёта итого с НДС
function calculateTotal(price, vatPercent) {
  let vat = price * vatPercent / 100;
  return price + vat;
}

// Функция форматирования цены
function formatPrice(amount) {
  return amount.toFixed(2) + " ₽";
}

// Используем функции вместе:
let originalPrice = 1000;
let discountedPrice = applyDiscount(originalPrice, 10); // 900
let totalPrice = calculateTotal(discountedPrice, 20);   // 1080
console.log("Итого к оплате:", formatPrice(totalPrice)); // "Итого к оплате: 1080.00 ₽"

Посмотрите, как каждая функция делает ровно одну вещь. Такой код легко читать, легко тестировать и легко изменять.

✅ Итоги урока

  • Функции нужны для переиспользования кода и декомпозиции задачи на части
  • Function Declaration — function name() {}: можно вызвать до объявления (hoisting)
  • Function Expression — const name = function() {};: нельзя вызвать до строки с присваиванием
  • return возвращает значение из функции и немедленно прекращает её выполнение
  • Ранний return — способ выйти из функции при нужном условии, делает код чище
  • Функция без return возвращает undefined — это частая причина ошибок
  • Важно понимать разницу: вызвать функцию и использовать её возвращаемое значение

В следующем уроке разберём параметры vs аргументы подробнее и научимся задавать значения по умолчанию. 🚀

Тест: Объявление функций и return

7 вопросов

Калькулятор площади прямоугольника

Напишите функцию rectangleArea(width, height), которая принимает ширину и высоту прямоугольника, и возвращает его площадь. Если хотя бы один из аргументов меньше или равен 0 — функция должна вернуть строку 'Некорректные размеры'. Используйте ранний return для проверки.

Максимум из трёх чисел

Напишите функцию maxOfThree(a, b, c), которая принимает три числа и возвращает наибольшее из них, не используя Math.max.