JavaScript: Модули
Пока программа маленькая, весь код можно хранить в одном файле. Такой подход удобен для простых примеров и небольших задач. Но со временем программа начинает расти. Когда кода становится много, ориентироваться в одном файле становится сложно. Реальные приложения состоят из десятков тысяч строк (как минимум) и сотен файлов.
Чтобы разделить программу на отдельные логические части, в JavaScript используют модули. Отдельный файл с кодом и есть модуль. А язык предоставляет механизмы, с помощью которых один файл может использовать функции и константы из другого.
export и import
Модуль сам решает, что отдать наружу. Для этого используют ключевое слово export. Другой файл подключает экспортированное через import.
Скорее всего, такие строки вы уже видели в начале некоторых заданий — теперь разберёмся, что они значат:
import { length } from 'hexlet-basics/string';
console.log(length('Hello!')); // => 6Эта строчка подключает функцию length из модуля hexlet-basics/string и делает её доступной в текущем файле.
Именованный импорт
Из одного модуля можно импортировать сразу несколько имён, перечислив их в фигурных скобках:
import { reverse, toUpperCase } from 'hexlet-basics/string';
console.log(reverse('hexlet')); // => telxeh
console.log(toUpperCase('hexlet')); // => HEXLETПосле такого импорта к функциям обращаются напрямую, по их именам. Это удобно: не нужно каждый раз писать, из какого модуля взята функция.
Экспорт по умолчанию
Чтобы что-то экспортировать, модуль помечает это словом export. Экспорт бывает двух видов. Именованный — экспортируемых имён может быть сколько угодно:
// string.js
const reverse = (s) => s.split('').reverse().join('');
const length = (s) => s.length;
export { reverse, length };И экспорт по умолчанию — он в модуле может быть только один. С таким экспортом вы уже сталкивались, когда определяли функции:
// sum.js
const sum = (a, b) => a + b;
export default sum;Импорт по умолчанию пишется без фигурных скобок, и имя при импорте можно выбрать любое:
import sum from './sum.js';
console.log(sum(2, 3)); // => 5Переименование при импорте
Иногда имя из модуля уже занято в текущем файле. Чтобы избежать конфликта, импорт можно переименовать через as:
import { reverse as reverseString } from 'hexlet-basics/string';
console.log(reverseString('hexlet')); // => telxehТеперь функция доступна под именем reverseString, а исходное имя reverse остаётся свободным.
Стандартные модули
У каждого языка есть набор готовых функций. В JavaScript бо́льшая часть из них доступна глобально и импорта не требует — например, объект Math для математики или console для вывода.
Но JavaScript исполняется в разных средах. В серверном окружении Node.js есть встроенные модули, которые нужно подключать. Их подключают с префиксом node: — например, модуль node:fs для работы с файлами:
import { readFile } from 'node:fs/promises';Готовые функции можно брать не только из стандартных, но и из сторонних модулей. О том, как они распространяются, поговорим в следующем уроке.
Задание
Реализуйте функцию mirror(). Она принимает строку, переворачивает её и переводит в верхний регистр, после чего возвращает результат.
Используйте функции reverse() и toUpperCase() из модуля hexlet-basics/string. Импорт нужно написать самостоятельно.
mirror('hello'); // => 'OLLEH'
mirror('Hexlet'); // => 'TELXEH'Подсказка
- В начале файла импортируйте нужные функции:
import { reverse, toUpperCase } from 'hexlet-basics/string'; - Сначала переверните строку, затем переведите результат в верхний регистр
Полезное
Ваше упражнение проверяется по этим тестам
// @ts-check
import { expect, test } from 'vitest';
import mirror from './index.js';
test('modules', () => {
expect(mirror('hello')).toBe('OLLEH');
expect(mirror('Hexlet')).toBe('TELXEH');
});Решение учителя откроется через:
20:00
