Модули — Основы программирования
Модули в JavaScript (ES6) реализованы на основе файлов, и находятся они с файлами в отношении "один-к-одному". Попросту говоря, какой-либо конкретный файл, содержащий js-код, можно смело считать отдельным модулем. При этом, как следует из вышенаписанного, один файл представляет лишь один модуль, в нём не может быть (по крайней мере, на текущий момент) организовано размещение одновременно нескольких модулей.
Любой ваш проект (программа, задача, приложение) — это код. И этого кода может быть очень много. Но даже в небольших по объёму проектах без должной структуризации кода весьма легко запутаться в используемых константах и переменных (далее — переменные), функциях и классах и допустить ошибки. Так вот, базовым и наиболее естественным средством структуризации вашего кода служит его разбиение на отдельные модули. И это помогает решить ряд задач и проблем:
- С использованием модулей ваш код становится легче писать, сопровождать и читать — в общем, его качество растёт по "всем фронтам". Конечно, для этого надо грамотно классифицировать код и осуществить его разбиение по модулям, но это тема, даже не статей, а целых книг. Тем не менее, даже построение на самом базовом уровне системы модулей, каждый из которых несёт чётко определённую функциональность (имеет свою зону ответственности) даёт по сравнению с неструктурированным кодом все те профиты, о которых писалось выше. Обратите внимание, как устроена каждая практика в наших курсах: в каждом упражнении есть модуль (один или несколько), в котором нужно написать программу (функцию); отдельный модуль выделен для тестирования вашего кода; возможны дополнительные модули, в которых содержатся вспомогательные функции.
- Разрешаются конфликты имён. А они неизбежно возникают, когда в коде используются от нескольких десятков до нескольких сотен (и более!) идентификаторов и все они находятся в одной общей области видимости. Теперь же, разделив код на модули, в каждом из которых свои собственные области видимости, никак не пересекающиеся между собой, вам не надо "держать и перебирать" в голове весь остальной код, не относящийся к модулю, с которым вы в настоящий момент работаете — очевидно, задача разрешения (предотвращения) конфликта имён кардинально упрощается.
- Меньше ошибок, выше надёжность. С помощью модулей осуществляется инкапсуляция кода. Модуль изолирует одну часть вашего проекта от других, одновременно предоставляя возможность контролируемого доступа к отдельным своим компонентам — "всему остальному миру" (другим модулям) будут видны только те переменные, функции и классы, которые вы сами посчитаете нужным экспортировать (инструкции export и/или default export ). Таким образом снижается вероятность непреднамеренного или злонамеренного изменения кода одной части программы из другой части, повышается уровень безопасности.
Далее будут подробно рассмотрены синтаксис модулей, способы и примеры экспортирования и импортирования.
Анализ кода
Почти все последующие уроки этого курса, а также все остальные курсы на Хекслете активно используют модули. Такой подход максимально приближает нас к реальной жизни, когда проекты состоят из сотен, а то и тысяч файлов и библиотек, которые активно пользуются друг другом.
При работе с модулями будет полезным сразу наработать некоторые модели поведения, позволяющие вам с легкостью определять, какой код вам доступен на исполнение, откуда пришел этот код и как его увидеть. Фидбек, который мы получаем от наших пользователей, говорит о том, что, как раз, в этом моменте больше всего затыков.
Ниже описан основной алгоритм, по которому нужно анализировать файл с кодом, над которым вы сейчас работаете. Этот алгоритм не является специфичным для работы в среде Хекслета, так нужно делать в принципе:
- Внимательно изучите все импорты, описанные в начале файла. Так вы узнаете, какие модули и функции доступны внутри вашего файла (не считая глобальных функций и модулей, которые доступны и без импорта, например, Math ).
- Попробуйте классифицировать импортируемые функции. Если импорт выглядит так from './. , то есть содержит ./ , значит импортируется модуль, содержимое которого находится в текущей файловой системе. Это автоматически означает несколько вещей. Первое, вы всегда можете открыть этот файл и посмотреть, что там написано, второе, вы не сможете импортировать этот модуль в другой среде, что очевидно, ведь этого файла там нет.
- Если from 'name' содержит только имя, без лидирующего ./ , это означает, что модуль подгружается либо из стандартной библиотеки nodejs , либо из установленных пакетов. Визуально невозможно отличить одно от другого. В данном случае необходимо проявить смекалку и попробовать загуглить имя таким способом nodejs name . Если в выдаче будет ссылка на официальную документацию, то значит это модуль ноды, если на репозиторий npm , значит это обычный пакет, который почти наверняка лежит на гитхабе, что можно проверить таким запросом github js name , где name это имя пакета.
Дополнительные возможности
Варианты импорта
Если из модуля экспортировано множество функций, то, как мы уже знаем, импортировать их можно с помощью такой строчки:
Иногда бывает удобнее импортировать функции в текущий модуль напрямую, без необходимости указывать исходный модуль, и достичь этого можно таким образом:
Часто встречаются ситуации, в которых нужно импортировать функции из нескольких разных модулей, но имена этих функций совпадают. Как мы помним из теории, это одна из ключевых целей модулей, предотвратить коллизии имен. Так вот, пока функции живут внутри своих модулей, эта коллизия разруливается автоматически, но при необходимости использовать эти функции в третьем модуле, нужен дополнительный механизм. Выражается он в том, что при импорте мы можем локально переименовать любую функцию, другими словами ей можно задать алиас.
Варианты экспорта
По умолчанию также можно экспортировать любую константу, что открывает такую возможность:
При этом снаружи это имя никак не используется, любой экспорт по умолчанию импортируется под любым именем.
Синтаксис экспорта по умолчанию таков, что после обязательных ключевых слов export default можно указать выражение, будь то константа:
или анонимная функция:
или даже просто литерал, например:
В отличие от именованного экспорта здесь после ключевых слов недопустимо указывать объявления переменных (с использованием const, let, var) и возможен только один дефолтный экспорт на модуль.
Экспорт и импорт в действии
donor.js — файл, в котором размещены экспортные функции. acceptor.js — файл, в котором происходит импорт функций.
Давайте наполним donor.js экспортными константами и функциями. Для полноты картины к именованному экспорту мы добавили ещё и экспорт по умолчанию (это допустимо, хотя и не принято так делать, по смыслу экспорта по умолчанию он должен быть единственным экспортом на модуль):
Теперь рассмотрим несколько вариантов, как можно импортировать эти переменные и функции (далее для краткости — функции) в модуль acceptor.js:
—> Импортируем все функции из donor.js в виде объекта, которому необходимо дать произвольный (соответствующий общим правилам именования переменных) псевдоним. Обращаемся к импортированным функциям как к свойствам этого объекта:
—> Сделаем выборочный импорт функций из donor.js. Для этого перечислим в фигурных скобках имена интересующих нас функций. Обращаемся к импортированным функциям по этим именам. При этом им можно давать псевдонимы, далее в текущем модуле доступ к таким функциям будет происходить только по псевдониму (это может пригодится в том случае, если в модуле уже существует функция с таким именем, для разрешения конфликта имён):
—> Импортируем из модуля donor.js значение по умолчанию. Для этого достаточно просто указать после ключевого слова import произвольное (наиболее подходящее и удобное) имя. В таком случае по этому имени можно будет обращаться к значению по умолчанию из импортируемого модуля:
Также есть возможность импортировать одновременно и значение по умолчанию и другие экспортированные компоненты. Это можно сделать несколькими способами, приведём примеры:
Модульная арифметика: что это такое и где применяется
![]()
В математике модульная арифметика представляет собой систему расчета для целых чисел, при помощи которой они «переворачиваются» при достижении определенного значения — модуля (или множественного числа оных). Современный подход к этому виду науки был развит Карлом Фридрихом Гауссом в его книге Disquisitiones Arithmeticae, опубликованной в 1801 году. Этим методом очень любят пользоваться специалисты по информатике, поскольку это очень интересно и открывает определенные новые возможности в операциях с числами.

Поскольку число часов начинается заново после того, как оно достигает 12, это арифметическое по модулю 12. Согласно приведенному ниже определению 12 соответствует не только 12, но и 0, поэтому можно также назвать время, называемое «12:00». «0:00». Ведь 12 совпадает с 0 по модулю 12.
Модульная арифметика может обрабатываться математически, путем введения конгруэнтного отношения к целым числам, которое совместимо с операциями над целыми числами: сложение, вычитание и умножение. Для положительного целого числа n два числа a и b называются конгруэнтными по модулю n, если их разность a — b кратна n (то есть, если существует целое число k такое, что a — b = kn).

Вычеты
В теоретической математике модульная арифметика является одной из основ теории чисел, затрагивающей почти все аспекты ее изучения, а также широко используется в теории групп, колец, узлов и абстрактной алгебре. В области прикладной математики она используется в компьютерной алгебре, криптографии, информатике, химии, изобразительном и в музыкальном искусстве.
Практика
Очень практичным применением является вычисление контрольных сумм в идентификаторах серийных номеров. Например некоторые общепринятые стандарты книг используют арифметику по модулю 11 (если выпущена до 1 января 2007 г.) или по модулю 10 (если выпущена до или после 1 января 2007 г.). Аналогичным образом, например, в Международных номерах банковских счетов (IBAN). Здесь используется арифметика по модулю 97 для выявления ошибок ввода пользователем в номерах банковских счетов.
В химии последняя цифра регистрационного номера CAS (уникальный идентификационный номер для каждого химического соединения) является контрольной цифрой. Она рассчитывается путем взятия последней цифры из первых двух частей регистрационного номера CAS, умноженной на 1, предыдущую цифру 2 раза, предыдущая цифра 3 раза и т. д., складывая все это и вычисляя сумму по модулю 10.
Что такое криптография? Дело в том, что она имеет весьма сильную связь с обсуждаемой темой. В криптографии законы модульной арифметики, непосредственно, лежат в основе систем с открытым ключом, таких как RSA и Диффи-Хелльман. Здесь она предоставляет конечные поля, которые лежат в основе эллиптических кривых. Используется в различных алгоритмах симметричного ключа, включая Advanced Encryption Standard (AES), Международный алгоритм шифрования данных и RC4.

Применение
Этот способ применяется в тех областях, где нужно читать цифры. Его разработали математики, а пользуются им все, особенно специалисты по информатике. Это хорошо описано в книгах вроде «Модульная арифметика для чайников». Впрочем, ряд специалистов рекомендует не воспринимать такую литературу всерьез.
В информатике модульная арифметика часто применяется в побитовых и других операциях, включающих циклические структуры данных фиксированной ширины. Ее очень любят использовать аналитики. Операция по модулю реализована во многих языках программирования и калькуляторах. В данном случае она является одним из примеров такого применения. Сравнение по модулю, деление с остатком и прочие приемы также применяются в программировании.
В музыке арифметика по модулю 12 используется при рассмотрении системы равного темперамента из двенадцати тонов, в которой происходит эквивалентность октавы и энгармоники. Иными словами, тональности в соотношении 1-2 или 2-1 эквивалентны. В музыке и других гуманитарных дисциплинах арифметика играет довольно значимую роль, но в учебниках информатики об этом обычно не пишут.

Метод приведения девяток
Метод приведения девяток предлагает быструю проверку десятичных арифметических вычислений, выполненных вручную. Он основан на модульной арифметике по модулю 9 и, в частности, на решающем свойстве 10 10 1.
существуют и другие примеры. Арифметическое по модулю 7 используется в алгоритмах, которые определяют день недели для конкретной даты. В частности, конгруэнтность Целлера и алгоритм «Судного дня» интенсивно используют арифметику по модулю 7.
Иные области применения
О модульной арифметике в криптографии уже было сказано. В этой сфере она попросту незаменима. В более общем смысле, модульная арифметика также находит применение в таких дисциплинах, как право, экономика (например, теория игр) и другие области социальных наук. Иными словами, там, где пропорциональное разделение и распределение ресурсов играет главную роль.

Поскольку модульная арифметика имеет такой широкий спектр применений, важно знать, насколько сложно решить систему сравнений. Линейная система конгруэнций может быть решена за полиномиальное время в форме исключения Гаусса. Подробнее это описывает теорема о линейной конгруэнции. Алгоритмы, такие как редукция Монтгомери, также существуют, чтобы позволить эффективно выполнять простые арифметические операции. Например, умножение и возведение в степень по модулю n, для больших чисел. Это очень важно знать для понимания того, что такое криптография. Ведь в ней как раз работают с подобными операциями.
Конгруэнция
Некоторые операции, такие как поиск дискретного логарифма или квадратичной конгруэнции, кажутся такими же сложными, как целочисленная факторизация, и, таким образом, являются отправной точкой для криптографических алгоритмов и шифрования. Эти проблемы могут быть NP-промежуточными.
Примеры
Ниже приведены три достаточно быстрые функции C — две для выполнения модульного умножения и одна для возведения в модулярные числа для целых чисел без знака, не превышающих 63 бита, без переполнения переходных операций.
Вскоре после обнаружения целых чисел (1, 2, 3, 4, 5 . ) становится очевидным, что они делятся на две группы:
- Четный: делится на 2 (0, 2, 4, 6 ..).
- Нечетное: не делится на 2 (1, 3, 5, 7…).
Почему это различие важно? Это начало абстракции. Мы замечаем свойства числа (например, четное или нечетное), а не только само число («37»).
Это позволяет нам исследовать математику на более глубоком уровне и находить отношения между типами чисел, а не конкретными.

Свойства числа
Быть «тройкой» — это просто еще одно свойство числа. Возможно, не так сразу полезно, как четное/нечетное, но оно есть. Мы можем создать правила типа «тринадцать х три вена = тринадцать» и так далее. Но это сводит с ума. Мы не можем делать новые слова все время.
Операция по модулю (сокращенно mod или «%» во многих языках программирования) является остатком при делении. Например, «5 mod 3 = 2», что означает 2 — остаток, когда вы делите 5 на 3.
При преобразовании повседневных терминов в математику «четное число» — это то, где оно равно «0 mod 2», то есть остаток равен 0 при делении на 2. Нечетное число равно «1 mod 2» (имеет остаток 1).

Четные и нечетные числа
Что такое четный х четный х нечетный х нечетный? Ну, это 0 x 0 x 1 x 1 = 0. На самом деле, вы можете видеть, умножается ли где-либо четное число, где весь результат будет равен нулю.
Хитрость модульной математики в том, что мы уже использовали ее для хранения времени — иногда ее называют «арифметикой часов».
Например: 7:00 (утра/вечера — не имеет значения). Где будет часовая стрелка через 7 часов?
Модуляции
(7 + 7) mod 12 = (14) mod 12 = 2 mod 12 [2 — это остаток, когда 14 делится на 12. Уравнение 14 mod 12 = 2 mod 12 означает, что 14 часов и 2 часа выглядят одинаково на 12-часовых часах. Они являются конгруэнтными, обозначенными знаком тройного равенства: 14 ≡ 2 mod 12.
Другой пример: сейчас 8:00. Где будет большая стрелка через 25 часов?
Вместо добавления 25 к 8, вы можете понять, что 25 часов — это просто «1 день + 1 час». Ответ прост. Итак, часы закончатся на 1 час вперед — в 9:00.
(8 + 25) мод 12 ≡ (8) мод 12 + (25) мод 12 ≡ (8) мод 12 + (1) мод 12 ≡ 9 мод 12. Вы интуитивно конвертировали 25 в 1 и добавили это к 8.
Используя часы в качестве аналогии, мы можем выяснить, работают ли правила модульной арифметики, а они работают.

Сложение/Вычитание
Допустим, два раза выглядят одинаково на наших часах («2:00» и «14:00»). Если мы добавим одинаковые х часов к обоим, что произойдет? Ну, они меняются на ту же сумму на часах! 2:00 + 5 часов ≡ 14:00 + 5 часов — оба покажут 7:00.
Зачем? Мы можем просто добавить 5 к 2 остаткам, которые оба имеют, и они продвигаются одинаково. Для всех конгруэнтных чисел (2 и 14) сложение и вычитание имеют одинаковый результат.
Труднее понять, остается ли умножение таким же. Если 14 ≡ 2 (мод 12), можем ли мы умножить оба числа и получить одинаковый результат? Давайте посмотрим, что произойдет, когда мы умножим на 3.
Ну, 2:00 * 3 × 6:00. Но что такое 14:00 * 3?
Помните, 14 = 12 + 2. Итак, мы можем сказать,
14 * 3 = (12 + 2) * 3 = (12 * 3) + (2 * 3)
Первую часть (12 * 3) можно игнорировать! Переполнение 12 часов, которое несет 14, просто повторяется несколько раз. Но кого это волнует? В любом случае мы игнорируем переполнение.

Умножение
При умножении имеет значение только остаток, то есть те же 2 часа для 14:00 и 2:00. Интуитивно понятно, что именно так я вижу, что умножение не меняет отношения с модульной математикой (вы можете умножить обе стороны модульного отношения и получить один и тот же результат).
Мы делаем это интуитивно, но приятно дать ему имя. У вас есть рейс, прибывающий в 3 часа дня. Он задерживается на 14 часов. Во сколько он приземлится?
14 ≡ 2 мод 12. Так что, стоит думать об этом как 2 часа, поэтому самолет приземлиться 5 часов утра. Решение простое: 3 + 2 = 5 утра. Это немного сложнее, чем простая операция по модулю, но принцип тот же.