Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Чистые функции

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

Детерминированность

Встроенная в JavaScript функция Math.random() возвращает случайное число от 0 до 1:

Math.random(); // 0.9337432365797949
Math.random(); // 0.5550694016887598

Функция нужная и полезная, но неудобная в отладке и тестировании. Это связано с тем, что для одних и тех же входных аргументов (отсутствие аргументов также попадает под это понятие), она может возвращать разные значения. Функции с таким поведением называются недетерминированными.

Например, недетерминированными являются функции, оперирующие системным временем. Так, функция Date.now() каждый раз возвращает новое значение:

// Возвращает текущие время в миллисекундах
Date.now(); // 1571909874844
Date.now(); // 1571909876648

А вот пример с аргументами. Представьте функцию getAge(), которая принимает на вход год рождения и возвращает возраст:

getAge(2000); // ?

Хотя прямо сейчас повторный запуск вернёт точно такое же значение, через год оно уже будет другим. То есть функция считается недетерминированной, если она ведёт себя так хотя бы единожды.

Детерминированные функции, напротив, ведут себя предсказуемо. Для одних и тех же входных данных они всегда выдают один и тот же результат. Именно такими являются функции в математике.

Интересно что, например, функция console.log() — детерминированная. Дело в том, что она всегда возвращает одно и то же значение для любых входных данных. Это значение undefined, а не то, что печатается на экран, как можно было бы подумать. Печать на экран — побочный эффект, о нём мы поговорим чуть позже.

console.log('Hexlet – Big Bang');

Вызов console.log('Hexlet - Big Bang') выполнил два действия:

  • Вывел сообщение Hexlet - Big Bag в терминал (или консоль браузера, в зависимости от среды выполнения)
  • Вернул значение undefined. Какое сообщение бы мы не печатали, возвращаемое значение всегда будет одно — undefined.

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

const getCurrentShell = () => process.env.SHELL;

getCurrentShell(); // /bin/bash

Функция getCurrentShell() обращается к переменной окружения SHELL. Но в разные моменты времени и в разных окружениях значение этой переменой может быть различным.

В общем случае нельзя сказать, что отсутствие детерминированности — абсолютное зло. Для работы многих программ и сайтов нужна функция возвращающая случайное число или вычисляющая текущую дату. С другой стороны, в нашей власти разделить код так, чтобы в нем было как можно больше детерминированных частей. Общая рекомендация при работе с детерминированностью звучит следующим образом: если есть возможность написать функцию так, что она будет детерминированной, то так и делайте. Не используйте глобальных переменных, создавайте функции, зависящие только от своих собственных аргументов.

Понятие "Детерминированность" не ограничивается программированием или математикой. Сквозь него можно рассматривать практически любой процесс. Например, подбрасывание монетки — недетерминированный процесс, его результат случаен.

Побочные эффекты (side effects)

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

const someFunction = () => {
  // Функция fetch выполняет HTTP-запрос
  // HTTP-запрос это побочный эффект
  fetch('https://ru.hexlet.io/courses');
};

Кроме того, побочными эффектами считаются изменения внешних переменных (например глобальных) и входных параметров в случае, когда они передаются по ссылке.

const someFunction = (obj) => {
  // Какая-то логика
  // Побочный эффект. Изменение входного аргумента.
  obj.key = 'value';
};

А вот вычисления (логика), напротив, не содержат побочных эффектов. Например, функция, суммирующая два переданных аргументами числа.

const sum = (num1, num2) => num1 + num2;

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

Без побочных эффектов невозможно написать ни одной полезной программы. Какие бы важные вычисления она ни делала, их результат должен быть как-то продемонстрирован. В самом простом случае его нужно вывести на экран, что автоматически приводит нас к побочным эффектам:

console.log(sum(4, 11)); // => 15

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

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

  1. Читает файл в самом начале работы программы.
  2. Записывает результат работы программы в новый файл.

Между этими двумя пунктами и происходит основная работа, которая содержит чистую алгоритмическую часть. Побочные эффекты, в таком случае, будут находиться только в верхнем слое приложения, а ядро, выполняющее основную работу, останется чистым от них.

Инкремент и декремент — единственные базовые арифметические операции в JS, которые обладают побочными эффектами (изменяют само значение в переменной). Именно поэтому с ними сложно работать в составных выражениях. Они могут приводить к таким сложноотлавливаемым ошибкам, что во многих языках вообще отказались от их введения (в Ruby и Python их нет). В JS стандарты кодирования предписывают их не использовать.

Чистые функции

Чистые функции в JavaScript

Идеальная функция с точки зрения удобства работы с ней называется чистой (pure). Чистая функция — это детерминированная функция, которая не производит побочных эффектов. Такая функция зависит только от своих входных аргументов и всегда ведёт себя предсказуемо.

Чистые функции обладают рядом ключевых достоинств:

  • Их просто тестировать. Достаточно передать на вход функции нужные параметры и посмотреть ожидаемый выход.
  • Их безопасно запускать повторно, что особенно актуально в асинхронном коде или в случае многопоточного кода.
  • Их легко комбинировать, получая новое поведение без необходимости переписывать программу (подробнее далее по курсу).

В хорошо спроектированных программах побочные эффекты стараются изолировать в небольшой части приложения так, чтобы большая часть кода была чистой.

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


Дополнительные материалы

  1. Побочные эффекты
  2. Детерминированная функция

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».