⚡ JavaScript

حلقة for في JavaScript (Node.js): دليل شامل

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

Что такое функция? Аналогия с рецептом

Представьте кулинарную книгу. В ней есть рецепт борща: "взять свёклу, картошку, капусту, сварить, добавить специи..." Каждый раз, когда вы хотите борщ, вы не изобретаете рецепт заново — вы открываете страницу и следуете инструкции.

Функция в программировании — это exactly рецепт. Один раз написали инструкцию — и можете применять её сколько угодно раз:

  • Имя функции — как название рецепта ("Борщ")
  • Параметры — "пустые поля" в рецепте ("добавить N граммов соли" — N можно менять)
  • Тело функции — сам рецепт, последовательность действий
  • Возвращаемое значение — результат (готовое блюдо)

Зачем это нужно? Главный принцип программирования — DRY: Don't Repeat Yourself (Не повторяй себя). Если один и тот же код встречается в нескольких местах — выносите его в функцию.

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

// Объявление функции (Function Declaration):
function поздороваться() {
  console.log("Привет!");
  console.log("Как дела?");
}

// Вызов функции (несколько раз!):
поздороваться(); // Привет! Как дела?
поздороваться(); // Привет! Как дела?
поздороваться(); // Привет! Как дела?

Разбор синтаксиса:

  • function — ключевое слово, говорим JavaScript: "Я объявляю функцию"
  • поздороваться — имя функции (придуманное нами). Правила именования такие же как у переменных
  • () — круглые скобки. В них будут параметры (пока пусто)
  • { ... } — фигурные скобки. Внутри — тело функции, код, который будет выполняться
  • поздороваться() — вызов функции. Скобки обязательны!

Параметры и аргументы

Параметр — это "пустое поле в рецепте". При вызове функции мы заполняем это поле конкретным значением (аргументом).

// Функция с одним параметром:
function поздороватьсяС(имя) {   // имя — параметр (пустое поле)
  console.log(`Привет, ${имя}!`);
}

поздороватьсяС("Маша");  // аргумент "Маша" заполняет параметр имя
поздороватьсяС("Петя");
поздороватьсяС("Мир");
// Вывод:
// Привет, Маша!
// Привет, Петя!
// Привет, Мир!

// Функция с несколькими параметрами:
function сложить(а, б) {
  console.log(`${а} + ${б} = ${а + б}`);
}

сложить(5, 3);   // 5 + 3 = 8
сложить(10, 20); // 10 + 20 = 30
сложить(1, 1);   // 1 + 1 = 2

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

Параметры по умолчанию

// Если аргумент не передан — используется значение по умолчанию:
function приветствие(имя = "незнакомец", время = "день") {
  console.log(`Добрый ${время}, ${имя}!`);
}

приветствие("Коля", "вечер"); // Добрый вечер, Коля!
приветствие("Таня");          // Добрый день, Таня!  (время = "день" по умолчанию)
приветствие();                // Добрый день, незнакомец!  (оба по умолчанию)

Возвращаемое значение: return

Пока наши функции просто что-то делали (выводили в консоль). Но функции могут ещё и возвращать результат — как рецепт, который в итоге даёт готовое блюдо.

// Функция без return только делает что-то (side effect):
function сказатьПривет() {
  console.log("Привет!"); // Делает вывод в консоль
}
let результат = сказатьПривет(); // "Привет!" выводится в консоль
console.log(результат);           // undefined (функция ничего не вернула)

// Функция с return возвращает значение:
function сложить(а, б) {
  return а + б; // ВЕРНУТЬ результат
}
let сумма = сложить(5, 3); // сумма теперь = 8
console.log(сумма);         // 8
console.log(сложить(10, 20)); // 30 (можно использовать прямо в выражениях)

// Практичный пример:
function рассчитатьСкидку(цена, процент) {
  let скидка = цена * (процент / 100);
  let итого = цена - скидка;
  return итого;
}

let ценаТовара = 1000;
let цена10 = рассчитатьСкидку(ценаТовара, 10); // 900
let цена25 = рассчитатьСкидку(ценаТовара, 25); // 750
console.log(`Со скидкой 10%: ${цена10} руб.`);
console.log(`Со скидкой 25%: ${цена25} руб.`);

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

function тест() {
  console.log("Это выполнится");
  return 42;
  console.log("Это НЕ выполнится"); // Недостижимый код
}
let x = тест(); // В консоли: "Это выполнится"
console.log(x); // 42

Функциональное выражение

Функцию можно записать в переменную — это называется функциональное выражение:

// Function Expression — функция как значение переменной:
const умножить = function(а, б) {
  return а * б;
};

console.log(умножить(3, 4)); // 12
console.log(умножить(5, 5)); // 25

// Разница с Function Declaration:
// Function Declaration можно вызвать ДО объявления:
console.log(сложить1(2, 3)); // 5 — работает! (hoisting)
function сложить1(а, б) { return а + б; }

// Function Expression нельзя вызвать до объявления:
// console.log(сложить2(2, 3)); // Ошибка! (ReferenceError)
const сложить2 = function(а, б) { return а + б; };

Стрелочные функции (Arrow Functions)

В ES2015 появился новый, более краткий синтаксис для функций — стрелочные функции. Они выглядят необычно поначалу, но очень удобны.

// Обычная функция:
const сложить = function(а, б) {
  return а + б;
};

// То же самое — стрелочная функция:
const сложить = (а, б) => {
  return а + б;
};

// Если тело функции — одно выражение, можно ещё короче:
const сложить = (а, б) => а + б;

// Один параметр — скобки не обязательны:
const удвоить = n => n * 2;

// Без параметров — скобки обязательны:
const привет = () => "Привет!";

// Примеры использования:
console.log(сложить(3, 4));  // 7
console.log(удвоить(5));     // 10
console.log(привет());       // Привет!

Зачем придумали стрелочные функции?

Две причины: краткость и поведение this. Краткость очевидна из примеров выше. С this разберёмся в уроке об объектах. Пока запомните: стрелочные функции удобны для коротких операций, особенно в массивах (следующий урок).

// Сравнение записей одной и той же логики:
const числа = [1, 2, 3, 4, 5];

// Длинная запись:
const удвоенные1 = числа.map(function(n) {
  return n * 2;
});

// Стрелочная:
const удвоенные2 = числа.map(n => n * 2);

console.log(удвоенные1); // [2, 4, 6, 8, 10]
console.log(удвоенные2); // [2, 4, 6, 8, 10]

Область видимости (Scope)

Область видимости — это "зона", где переменная существует и доступна. Аналогия: переменная, объявленная в комнате, существует только в этой комнате. Из соседней комнаты её не видно.

// Глобальная переменная — видна везде:
let глобальная = "Я глобальная";

function мояФункция() {
  // Локальная переменная — видна только внутри функции:
  let локальная = "Я локальная";

  console.log(глобальная); // "Я глобальная" — видно!
  console.log(локальная);  // "Я локальная" — видно!
}

мояФункция();
console.log(глобальная); // "Я глобальная" — видно
// console.log(локальная); // ReferenceError — не видно из глобальной зоны!

// Переменная в блоке (if, for, while):
if (true) {
  let блочная = "Я в блоке";
  console.log(блочная); // "Я в блоке" — видно внутри блока
}
// console.log(блочная); // ReferenceError — не видно вне блока!

// ВАЖНО: var не уважает блоки (ещё одна причина не использовать var):
if (true) {
  var старая = "Я var";
}
console.log(старая); // "Я var" — var "утёк" из блока!

Функции-колбэки (Callbacks)

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

Аналогия: вы оставляете записку другу "когда придёт посылка, позвони мне" — номер телефона это ваш callback. Друг "вызывает вас обратно" в нужный момент.

// Простой пример колбэка:
function выполнить(действие) {
  console.log("Начинаем...");
  действие(); // Вызываем переданную функцию
  console.log("Готово!");
}

function сказатьПривет() {
  console.log("Привет!");
}

function сказатьПока() {
  console.log("Пока!");
}

выполнить(сказатьПривет); // Начинаем... Привет! Готово!
выполнить(сказатьПока);   // Начинаем... Пока! Готово!

// Чаще всего колбэки передают анонимно (без имени):
выполнить(function() {
  console.log("Анонимная функция!");
});

// Или через стрелочную функцию:
выполнить(() => console.log("Стрелочный колбэк!"));

Практический колбэк: setTimeout

// setTimeout — выполнить функцию через N миллисекунд:
console.log("Старт");

setTimeout(function() {
  console.log("Это выполнится через 2 секунды");
}, 2000); // 2000 миллисекунд = 2 секунды

console.log("Конец");

// Вывод:
// Старт
// Конец
// Это выполнится через 2 секунды (через 2 сек!)

// Стрелочная запись:
setTimeout(() => console.log("Привет через секунду!"), 1000);

Обратите внимание на порядок вывода! "Конец" выводится раньше, чем текст из setTimeout. Это потому что JavaScript не ждёт таймера — он продолжает выполнение и "вспоминает" про setTimeout позже. Это называется асинхронность — подробнее в последнем уроке курса.

IIFE: самовызывающаяся функция

IIFE (Immediately Invoked Function Expression) — функция, которая вызывает себя сама немедленно после объявления. Использовалась для создания изолированной области видимости (до появления модулей):

// Обычная функция — объявляем, потом вызываем:
function обычная() {
  console.log("Обычная");
}
обычная();

// IIFE — объявляем и сразу вызываем:
(function() {
  let секретнаяПеременная = "Никто снаружи меня не видит";
  console.log("IIFE выполнилась!");
  console.log(секретнаяПеременная);
})(); // <-- скобки в конце запускают функцию

// Стрелочная IIFE:
(() => {
  console.log("Стрелочная IIFE!");
})();

В современном коде IIFE нужны реже, но вы встретите их в старых проектах.

Практический пример: игра "Угадай число"

// Функция для генерации случайного числа:
function случайноеЧисло(мин, макс) {
  return Math.floor(Math.random() * (макс - мин + 1)) + мин;
}

// Функция для проверки угадывания:
function проверить(загаданное, угаданное) {
  if (угаданное === загаданное) {
    return "победа";
  } else if (угаданное < загаданное) {
    return "больше";
  } else {
    return "меньше";
  }
}

// Основная игра:
function игра() {
  const секретноеЧисло = случайноеЧисло(1, 10);
  let попыток = 0;
  let угадал = false;

  while (!угадал && попыток < 5) {
    let ввод = prompt(`Угадай число от 1 до 10 (попытка ${попыток + 1}/5):`);
    let число = Number(ввод);
    попыток++;

    let результат = проверить(секретноеЧисло, число);

    if (результат === "победа") {
      alert(`🎉 Правильно! Ты угадал за ${попыток} попыток!`);
      угадал = true;
    } else if (результат === "больше") {
      alert("Загаданное число больше!");
    } else {
      alert("Загаданное число меньше!");
    }
  }

  if (!угадал) {
    alert(`Не угадал. Загаданное число было ${секретноеЧисло}`);
  }
}

игра(); // Запускаем игру!

Это уже настоящая маленькая игра! Обратите внимание, как задача разбита на три функции: одна генерирует число, другая проверяет угадывание, третья управляет игровым процессом. Каждая делает одно дело — это хороший стиль программирования.

Типичные ошибки новичков

  • Забыть скобки при вызове. поздороваться — это ссылка на функцию (не вызов). поздороваться() — вызов функции. Без скобок функция не выполнится.
  • Не использовать return. Если нужен результат — не забывайте return. Без него функция вернёт undefined.
  • Код после return. После return выполнение функции заканчивается. Код ниже не выполнится.
  • Путать параметры и аргументы. Параметр — имя в объявлении. Аргумент — значение при вызове. Путаница в терминах не страшна, но понимать разницу важно.
  • Слишком длинные функции. Если функция делает больше одной вещи — разбейте её на несколько. Каждая функция должна делать одно дело.
  • Неговорящие имена. function f(x) vs function рассчитатьНалог(сумма). Второй вариант читается как книга.

Итого

В этом уроке мы узнали:

  1. Функция — именованный блок кода, который можно выполнять многократно.
  2. Параметры — переменные-"заглушки" в определении функции. Аргументы — конкретные значения при вызове.
  3. return — возвращает значение из функции. После return функция завершается.
  4. Параметры по умолчанию — значение, если аргумент не передан.
  5. Стрелочные функции — краткий синтаксис: const f = (а, б) => а + б.
  6. Область видимости — переменные внутри функции не видны снаружи.
  7. Колбэки — функции, переданные как аргументы другим функциям.
  8. IIFE — самовызывающаяся функция для изоляции кода.

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