Функция — именованный блок кода, который принимает данные через параметры, выполняет действия и возвращает результат оператором return; без return она возвращает undefined. В JavaScript функцию можно объявить через function, записать как выражение или как стрелочную функцию (a, b) => a + b. Переменные, объявленные внутри функции, снаружи не видны, а вложенная функция помнит переменные внешней даже после её завершения — это называется замыканием.
После материала вы сможете
- написать функцию тремя способами — объявлением, выражением и стрелочной — и объяснить, чем они отличаются при поднятии
- задать параметры по умолчанию и rest-параметр и вернуть значение через
return - объяснить область видимости и замыкание на примере счётчика
- передать функцию как колбэк в
mapиfilterи разложить скрипт на чистые функции
Что знать заранее
Проверено на
Node.js 24 LTS (24.18.0)Microsoft Edge 155
Сверено с документацией: 11 октября 2026 г.
Содержание
Зачем нужны функции
В прошлых уроках расчёт чаевых, скидки и доставки повторялся почти в каждом примере. Каждый повтор — место, где можно ошибиться, и место, которое придётся исправлять, если правило изменится. Функция решает обе проблемы: вы один раз описываете действие, даёте ему имя и дальше вызываете по имени с разными данными. MDN описывает функцию как набор инструкций, который выполняет задачу или вычисляет значение: у функции есть вход и есть результат, связанный со входом.
function calcTip(bill, percent) {
return Math.round(bill * percent / 100);
}
console.log(calcTip(12500, 10)); // → 1250
console.log(calcTip(8990, 15)); // → 1349
console.log(calcTip(4000, 5)); // → 200calcTip— имя функции. Хорошее имя — глагол, который говорит, что функция делает:calcTip,formatPrice,isPaid.billиpercentв скобках — параметры: имена для значений, которые функция получит при вызове.calcTip(12500, 10)— вызов. Числа в скобках — аргументы:12500попадает вbill,10— вpercent.returnвозвращает результат туда, откуда функцию вызвали, — здесь вconsole.log.
Объявление, выражение и стрелочная функция
В JavaScript есть три основных способа создать функцию. Результат у них похожий, различаются синтаксис и пара важных деталей.
// 1. Объявление функции (function declaration)
function toTiyn(tenge) {
return Math.round(tenge * 100);
}
// 2. Функциональное выражение (function expression)
const toTenge = function (tiyn) {
return tiyn / 100;
};
// 3. Стрелочная функция: короткая запись без return…
const formatPrice = (tenge) => `${tenge} ₸`;
// …и с телом в фигурных скобках — тогда return обязателен
const priceWithDiscount = (price, percent) => {
const discount = Math.round(price * percent / 100);
return price - discount;
};
console.log(toTiyn(1999.9)); // → 199990
console.log(toTenge(199990)); // → 1999.9
console.log(formatPrice(4990)); // → 4990 ₸
console.log(priceWithDiscount(4990, 10)); // → 4491Объявление (declaration)
- Как выглядит
- function toTiyn(tenge) { … }
- Особенности
- Поднимается: её можно вызвать выше строки, где она объявлена
Выражение (expression)
- Как выглядит
- const toTenge = function (tiyn) { … };
- Особенности
- Функция — значение переменной; вызвать можно только после этой строки
Стрелочная (arrow)
- Как выглядит
- const formatPrice = (tenge) => …;
- Особенности
- Короткая запись; без фигурных скобок результат возвращается сам; нет своего this
Поднятие (hoisting) работает только для объявлений. По MDN, интерпретатор поднимает объявление функции целиком в начало области видимости, поэтому вызов выше объявления работает. Функция-выражение и стрелочная функция — это значения переменных const, и до строки объявления их использовать нельзя:
console.log(double(4)); // → 8
function double(n) {
return n * 2;
}
console.log(half(4)); // ReferenceError: стрелочная функция ещё не создана
const half = (n) => n / 2;$ node hoisting.js
8
…\first-js\hoisting.js:7
console.log(half(4)); // ReferenceError: стрелочная функция ещё не создана
^
ReferenceError: Cannot access 'half' before initialization
at …
Node.js v24.18.0У стрелочных функций есть ограничения: по MDN, у них нет собственного this и их не используют как методы объектов и конструкторы. В этом уроке это неважно: для коротких расчётов и колбэков стрелочные функции — привычный и удобный выбор.
Параметры: значения по умолчанию и rest
Если при вызове не передать аргумент, параметр получит undefined. Лишние аргументы функция просто не использует. Чтобы не проверять undefined вручную, параметру задают значение по умолчанию прямо в объявлении: name = "гость". По MDN, значение по умолчанию подставляется, только если аргумент не передан или равен undefined, — null считается переданным значением.
function greet(name = "гость", greeting = "Здравствуйте") {
return `${greeting}, ${name}!`;
}
console.log(greet("Алия")); // → Здравствуйте, Алия!
console.log(greet()); // → Здравствуйте, гость!
console.log(greet(undefined, "Привет")); // → Привет, гость!
console.log(greet(null)); // → Здравствуйте, null!
// rest-параметр собирает все переданные значения в массив
function sum(...prices) {
let total = 0;
for (const price of prices) {
total += price;
}
return total;
}
console.log(sum(1600, 1200, 500)); // → 3300
console.log(sum()); // → 0Rest-параметр ...prices собирает все переданные аргументы в массив. Он нужен, когда заранее неизвестно, сколько значений придёт: цен в чеке может быть одна, а может быть двадцать. Rest-параметр может быть только последним в списке.
return и функция без возврата
return делает две вещи: возвращает значение и сразу завершает функцию. Код после выполненного return не выполняется. Этим удобно пользоваться для ранних выходов: сначала отсечь особый случай, потом описать основной.
function deliveryCost(total) {
if (total >= 15000) {
return 0; // функция заканчивается здесь
}
return 1500;
}
function logOrder(id) {
console.log(`Заказ ${id}`); // ничего не возвращает
}
console.log(deliveryCost(23500)); // → 0
console.log(deliveryCost(9000)); // → 1500
const result = logOrder(1042); // → Заказ 1042
console.log(result); // → undefinedЕсли в функции нет return или он записан без значения, функция возвращает undefined. Это частый источник ошибок у новичков: функция «что-то посчитала» и вывела в консоль, но в переменную попал undefined. Вывод в консоль и возврат значения — разные действия: console.log показывает значение человеку, return передаёт его дальше в программу.
Область видимости и замыкания
Область видимости (scope) — часть программы, где переменная доступна. По MDN, функция создаёт свою область: переменные, объявленные внутри, снаружи не видны. Блок в фигурных скобках — тело if или цикла — тоже создаёт область для let и const. Изнутри видно всё, что снаружи, но не наоборот.
const city = "Алматы"; // глобальная область видимости
function describeOrder(id) {
const orderStatus = "оплачен"; // видна только внутри функции
if (id > 1000) {
const note = "новый клиент"; // видна только внутри блока if
console.log(`${id}: ${orderStatus}, ${note}, ${city}`);
}
}
describeOrder(1042); // → 1042: оплачен, новый клиент, Алматы
console.log(typeof orderStatus); // → undefined
// Параметр с тем же именем «затеняет» внешнюю переменную
let total = 100;
function addTip(total) {
total = total + 10;
return total;
}
console.log(addTip(50)); // → 60
console.log(total); // → 100$ node scope-error.js
…\first-js\scope-error.js:6
console.log(orderId);
^
ReferenceError: orderId is not defined
at …
Node.js v24.18.0Теперь главное следствие. Функция, созданная внутри другой функции, сохраняет доступ к её переменным — даже когда внешняя функция уже завершилась. MDN определяет замыкание (closure) как сочетание функции и её лексического окружения — переменных, которые были видны в месте её создания.
function createCounter() {
let count = 0; // живёт, пока жива возвращённая функция
return () => {
count++;
return count;
};
}
const nextTicket = createCounter();
console.log(nextTicket()); // → 1
console.log(nextTicket()); // → 2
const otherQueue = createCounter();
console.log(otherQueue()); // → 1
console.log(nextTicket()); // → 3
// Функция, которая создаёт функции с «запомненным» параметром
function makeDiscount(percent) {
return (price) => Math.round(price * (100 - percent) / 100);
}
const studentPrice = makeDiscount(15);
const staffPrice = makeDiscount(30);
console.log(studentPrice(2000)); // → 1700
console.log(staffPrice(2000)); // → 1400Каждый вызов createCounter создаёт новую переменную count, и возвращённая функция держит именно её. Поэтому у nextTicket и otherQueue независимые счёта. Изменить count снаружи нельзя: доступ к ней есть только у возвращённой функции. Так замыкания помогают прятать данные и создавать функции «с настройками», как studentPrice и staffPrice.
Функции как значения: колбэки, map и filter
Функция в JavaScript — такое же значение, как число или строка: её можно положить в переменную, передать в другую функцию и вернуть из функции. Функцию, которую передают другой функции, чтобы та её вызвала, называют колбэком (callback). Самые частые примеры — методы массивов filter и map.
const menu = [
{ name: "Капучино", price: 1600 },
{ name: "Латте", price: 1800 },
{ name: "Американо", price: 1200 },
{ name: "Раф", price: 2200 },
];
// filter оставляет элементы, для которых функция вернула true
const affordable = menu.filter((item) => item.price < 1700);
// map превращает каждый элемент в новый
const names = affordable.map((item) => item.name);
console.log(names.join(", ")); // → Капучино, Американо
// Объект из стрелочной функции — в круглых скобках
const raised = menu.map((item) => ({ ...item, price: item.price + 200 }));
console.log(raised[0].price); // → 1800
console.log(menu[0].price); // → 1600
// Свою функцию тоже можно передать как значение
const formatPrice = (tenge) => `${tenge} ₸`;
console.log(menu.map((item) => item.price).map(formatPrice).join(" | ")); // → 1600 ₸ | 1800 ₸ | 1200 ₸ | 2200 ₸filterвызывает колбэк для каждого элемента и оставляет те, для которых он вернул истинное значение.mapвызывает колбэк для каждого элемента и собирает новый массив из того, что колбэк вернул.- Оба метода создают новый массив, а
filterпо MDN возвращает поверхностную копию: сами объекты внутри — те же. - Чтобы вернуть объект из короткой стрелочной функции, оберните его в круглые скобки:
(item) => ({ ...item }). Без скобок фигурные скобки будут прочитаны как тело функции.
Чистые функции и побочные эффекты
Побочный эффект — любое действие функции, кроме возврата значения: изменение внешней переменной, вывод в консоль, запись в файл, запрос к серверу. Функцию без побочных эффектов, результат которой зависит только от аргументов, называют чистой. Её проще проверять: одинаковые аргументы всегда дают одинаковый результат.
// Нечистая функция: читает и меняет внешнюю переменную
let cartTotal = 0;
function addToCart(price) {
cartTotal += price;
return cartTotal;
}
console.log(addToCart(1600)); // → 1600
console.log(addToCart(1600)); // → 3200
// Чистая функция: результат зависит только от аргументов
const addPrice = (total, price) => total + price;
console.log(addPrice(0, 1600)); // → 1600
console.log(addPrice(0, 1600)); // → 1600Побочные эффекты нужны — без них программа ничего не покажет и не сохранит. Совет, которому мы следуем в проектах InterLAB: держать расчёты в чистых функциях, а вывод, запросы и запись собирать в немногих местах. Тогда скидку или доставку можно проверить одним вызовом, не запуская всю программу.
С функциями у вас есть все базовые конструкции языка: значения, условия, циклы и способ собирать из них именованные действия. Дальше по траектории — структуры данных: массивы, объекты, Map и Set и их методы. Когда функции начнут работать с сетью и файлами, понадобится урок об обработке ошибок, а замыкания пригодятся в рецепте debounce и throttle.
Как проверено2 · пройденосверено 11 октября 2026 г.
- запущено, работает
tip-function, three-forms, params, return, scope, closure, callbacks, pure + решения tip-default, order-functions, queue (RU и EN)
node 24.18.0: stdout построчно сверен с комментариями // → (check-arrows), как .js и как .mjs; те же файлы выполнены в Microsoft Edge 155 headless — вывод совпал
- запущено, работает
hoisting.js, scope-error.js
node 24.18.0: 8, затем ReferenceError: Cannot access 'half' before initialization; ReferenceError: orderId is not defined; в Edge 155 — те же сообщения с Uncaught. shellsession в статье — реальный вывод с сокращённым путём
«Запущено» — код выполнен во временном проекте или контейнере, вывод в статье взят из прогона. «Частично» — проверено с заглушками вместо внешних сервисов. «Не запускалось» — нужны устройство, аккаунт или ключ; шаги сверены с официальной документацией. Файлы проверочного проекта и логи запусков сохранены в архиве InterLAB.