Урок 2 · JavaScript
Функции: не повторяй один и тот же код
Функция в JavaScript — именованный блок кода, который выполняет одну задачу и запускается по вызову. Её описывают один раз, а вызывают сколько угодно: greet('Маша'). На вход функция получает параметры, а результат отдаёт через return.
- Объявление описывает функцию, вызов
name()её запускает. - Параметры — имена в скобках при объявлении, аргументы — значения при вызове.
returnвозвращает результат и сразу завершает функцию.- Стрелочная запись
(a, b) => a + bудобна для коротких функций и колбэков. - Переменные внутри функции не видны снаружи.
Зачем этот урок сейчас
Как только одно и то же действие нужно в двух местах — посчитать цену, показать сообщение, проверить поле, — появляется соблазн скопировать код. Через неделю правка в одном месте забудется в другом. Функция собирает действие под одним именем, и программа начинает читаться как список понятных шагов.
Объявление и вызов
function sayHello() {
console.log('Привет, веб!');
}
sayHello(); // Привет, веб!
sayHello(); // Привет, веб!Сначала функцию объявляют: ключевое слово function, имя, скобки и тело в фигурных скобках. Пока её не вызвали, код внутри не выполняется. Вызов — имя и круглые скобки. Без скобок sayHello — это сама функция как значение, она не запустится.
Параметры и аргументы
function greet(name, greeting = 'Привет') {
console.log(`${greeting}, ${name}!`);
}
greet('Маша'); // Привет, Маша!
greet('Илья', 'Добрый день'); // Добрый день, Илья!name и greeting — параметры, переменные внутри функции. 'Маша' — аргумент, значение, переданное при вызове. Значение по умолчанию подставляется, если аргумент не передали или передали undefined; пустая строка и 0 не заменяются. Если параметров больше трёх, удобнее передать один объект: createUser({ name, email, role }).
return: как вернуть результат
function sum(a, b) {
return a + b;
}
const total = sum(12, 8);
console.log(total); // 20
function getDiscount(price) {
if (price < 1000) return 0; // ранний выход
return price * 0.1;
}console.log только показывает значение в консоли — дальше в программу оно не попадает. return отдаёт значение туда, где функцию вызвали, и сразу завершает её: код после return не выполняется. Функция без return возвращает undefined. Ранний return для особого случая избавляет от глубоко вложенных if.
Три способа записать функцию
// объявление функции
function square(n) { return n * n; }
// функциональное выражение
const cube = function (n) { return n * n * n; };
// стрелочная функция
const double = (n) => n * 2;
const makeUser = (name) => ({ name, active: true }); // объект — в круглых скобках| Запись | Можно вызвать до объявления | Свой this |
|---|---|---|
function name() {} | да (всплытие) | да |
const f = function () {} | нет | да |
const f = () => {} | нет | нет, берёт снаружи |
Стрелочная функция с одним выражением возвращает его без return. Если открыть фигурные скобки, return нужен снова — частая ошибка новичков.
Область видимости
const rate = 0.2; // внешняя переменная видна внутри
function tax(price) {
const result = price * rate; // локальная, снаружи не видна
return result;
}
tax(1000); // 200
console.log(result); // ReferenceError: result is not definedПеременные, объявленные внутри функции через let или const, живут только в ней. Функция видит переменные снаружи, но лучше получать данные через параметры: так её проще проверить и переиспользовать. Если функция меняет внешние переменные, это легко пропустить, когда она вызывается из трёх мест.
Функция как значение и колбэки
const prices = [100, 250, 400];
const withTax = prices.map((price) => price * 1.2);
button.addEventListener('click', handleClick); // передаём функцию, не вызов
setTimeout(() => console.log('Прошла секунда'), 1000);В JavaScript функцию можно положить в переменную и передать другой функции. Функцию, которую вызовут потом, называют колбэком. Так работают map, обработчики событий и таймеры. Главное правило: передавай функцию (handleClick), а не результат её вызова (handleClick()).
Хорошая функция
Имя — глагол, описывающий действие: formatPrice, isEmailValid, openMenu. Если имя получается «обработатьДанные», внутри смешано несколько задач — раздели их. Функция, которая считает, не должна искать элементы на странице; функция, которая показывает результат, не должна считать.
function formatPrice(amount) {
return new Intl.NumberFormat('ru-RU', {
style: 'currency', currency: 'RUB', maximumFractionDigits: 0,
}).format(amount);
}
formatPrice(1800); // '1 800 ₽'Такую функцию можно проверить одной строкой в консоли — подключай её к кнопке только после этого.
function или стрелочная функция
Отдельные именованные функции программы: их видно в стеке ошибок, их можно вызвать до объявления, у них свой this для методов.
Короткие колбэки для map, filter, обработчиков и таймеров. Нет своего this — удобно внутри методов и классов.
Частые ошибки
- Забывают скобки при вызове:
greet— функция,greet()— её запуск. - Ждут, что
console.logвернёт значение, и получают undefined. - Открывают фигурные скобки в стрелочной функции и забывают return.
- Передают в обработчик вызов
handleClick()вместо самой функции. - Пишут одну огромную функцию, которая и считает, и рисует, и отправляет.
Доступность
Функции не видны пользователю, но от них зависит, как ведёт себя интерфейс. Если функция меняет содержимое страницы (показывает ошибку, результат расчёта), выводи текст в элемент с aria-live, чтобы скринридер его объявил. Обработчики вешай на кнопки и ссылки, а не на div: тогда функция запустится и с клавиатуры.
Поддержка браузерами
Объявления и выражения функций работают везде. Стрелочные функции, значения параметров по умолчанию и шаблонные строки поддерживаются всеми актуальными браузерами с 2016–2017 годов.
Практика
Напиши функцию getFinalPrice(price, discount = 0), которая возвращает цену со скидкой в процентах и не уходит ниже нуля. Затем напиши функцию formatPrice, которая превращает число в строку «1 800 ₽», и выведи в консоль итог для цены 2000 со скидкой 10.
Показать решение
function getFinalPrice(price, discount = 0) {
const result = price - (price * discount) / 100;
return Math.max(0, result);
}
function formatPrice(amount) {
return new Intl.NumberFormat('ru-RU', {
style: 'currency', currency: 'RUB', maximumFractionDigits: 0,
}).format(amount);
}
console.log(formatPrice(getFinalPrice(2000, 10))); // '1 800 ₽'Частые вопросы
Чем параметр отличается от аргумента?
Параметр — имя в скобках при объявлении функции. Аргумент — конкретное значение, переданное при вызове.
Что вернёт функция без return?
undefined. Если результат нужен дальше в программе, его возвращают через return.
Когда использовать стрелочную функцию?
Для коротких функций и колбэков: в map, filter, обработчиках событий, таймерах. Для крупных именованных функций привычнее обычное объявление.
Почему функцию можно вызвать до её объявления?
Объявления через function name() {} всплывают: движок узнаёт о них до выполнения кода. Функции в переменных через const так не работают.
Почему переменная из функции не видна снаружи?
Переменные, объявленные внутри функции, существуют только в ней. Чтобы получить значение снаружи, верни его через return.