</> Praktum

Главная / JavaScript / Функции JavaScript

Урок 2 · JavaScript

Функции: не повторяй один и тот же код

Редакция PraktumОбновлено 15 минут на урок с практикойУровень: новичок

Функция в 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 или стрелочная функция

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.

Источники