JavaScript / 39 минут

Функции и область видимости

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

В процессе Теория: впереди Практика: впереди Тест: впереди
07 / 22
После этой главы
  • Передавайте аргументы, возвращайте значения и используйте замыкания.
  • Применить тему в задаче «Функции и область видимости» и объяснить граничные случаи.

Около 9 минут на чтение и разбор примеров. Практика — отдельно, в своём темпе.

Контракт функции

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

Параметры объявляются в определении, аргументы передаются при вызове. Они не обязаны иметь одинаковые имена с переменными вызывающего кода. Передача числа создаёт локальную связь параметра с этим значением. Передача объекта создаёт связь с тем же объектом, поэтому изменение его свойства может быть видно снаружи. Это не означает, что функция способна переназначить внешнюю переменную простым присваиванием своему параметру.

JavaScript
function multiply(price, count) {
  return price * count;
}
const ticketPrice = 250;
console.log(multiply(ticketPrice, 3)); // 750

Возврат и завершение вызова

return передаёт результат вызывающему коду и завершает текущий вызов. Инструкции после выполненного return в той же ветви не исполняются. Если return отсутствует или написан без выражения, результатом будет undefined. Поэтому функцию, которая только печатает правильное число, нельзя считать функцией расчёта: другой код не получает её вычисленный результат через вызов.

Следите за переводом строки сразу после return. Автоматическая вставка точки с запятой может завершить возврат раньше предполагаемого объекта. Начинайте выражение на той же строке или ставьте открывающую скобку рядом с return. При раннем выходе для некорректного ввода сначала обработайте отказ, а затем описывайте основной сценарий без лишней вложенности.

JavaScript
function label(name) {
  if (!name) return 'Гость';
  return `Привет, ${name}`;
}
console.log(label('')); // Гость
console.log(label('Анна')); // Привет, Анна

Формы объявления и стрелочные функции

Function declaration позволяет объявить именованную функцию. Function expression создаёт функцию как значение выражения; её можно сохранить в переменной и передать дальше. Стрелочная функция удобна для короткого преобразования и имеет особенности this, которые разбираются отдельно. Она не является просто сокращённым написанием обычной функции во всех ситуациях.

JavaScript
function square(value) { return value * value; }
const double = function (value) { return value * 2; };
const triple = value => value * 3;
const wrap = value => ({ value });

У стрелки с телом-выражением результат возвращается неявно. Если добавлены фигурные скобки блока, нужен явный return. Объект в кратком теле оборачивают круглыми скобками, иначе фигурные скобки будут разобраны как блок. Выбирайте форму, в которой легко увидеть вход и результат; сложный алгоритм не становится понятнее от превращения в одну длинную стрелку.

Область видимости и параметры по умолчанию

Локальные переменные функции не становятся глобальными. Вложенный блок может читать внешние имена, а внешний блок не видит объявления внутри вложенного. При одинаковом имени во вложенной области возникает затенение. Оно допустимо, но иногда скрывает ошибку: разработчик думал, что меняет внешний счётчик, а создал новую переменную с тем же именем.

Параметр по умолчанию используется при undefined или отсутствии аргумента, но не при null, нуле или пустой строке. Это полезное отличие от замены через ||. Rest-параметр собирает оставшиеся аргументы в массив. Он должен быть последним формальным параметром. Распаковка массива при вызове через spread похожа по записи, но делает обратное действие — передаёт элементы как отдельные аргументы.

JavaScript
function greet(name = 'Гость') { return `Привет, ${name}`; }
function sum(...values) { return values.reduce((a, b) => a + b, 0); }
console.log(greet(undefined)); // Привет, Гость
console.log(greet('')); // Привет,
console.log(sum(...[2, 3, 4])); // 9

Функции как данные и побочные эффекты

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

Чистая функция не меняет внешнее состояние и для одинакового входа возвращает одинаковый результат. Такой код проще проверять и переиспользовать. Не вся программа может быть чистой: где-то нужно читать ввод, отправлять запрос и сохранять данные. Полезная архитектура оставляет эти действия на понятных границах и отделяет их от расчётов. Логирование, изменение переданного объекта и чтение текущего времени тоже влияют на рассуждение о поведении.

Разбор практической задачи

В практике этого урока нужно вернуть сумму квадратов двух чисел. Выделите вычисление квадрата в небольшую функцию или выразите его непосредственно в solve; оба подхода должны сохранять один контракт. Не перепутайте сумму квадратов с квадратом суммы: для 2 и 3 это 13 и 25 соответственно. Внешний код должен получить число через return, а не только увидеть его в консоли.

Проверьте пустой вход, один элемент и несколько разных значений. Не вводите глобальный аккумулятор, который переживёт вызов: проверяющая программа вызывает solve несколько раз в одном процессе. Для самостоятельной тренировки перепишите одну функцию тремя формами объявления и объясните различия в this и доступности объявления. Затем выделите чистый расчёт из функции, которая одновременно считает, выводит и записывает результат.

Загружаем редактор…

Музыка: Reverie — Scott Buckley · CC BY 4.0