Экспорт и импорт функций в JavaScript
TL;DR
Экспорт и импорт функций — стандартный способ разделять и повторно использовать код в JavaScript. Модули (ESM) делают код чище, позволяют шарить функции между файлами, оптимизировать сборку и упрощают тестирование. В статье — пошаговые примеры, советы по именованию, переходу с CommonJS, чек-листы для ролей и диаграмма принятия решения.
Сегодня JavaScript — ключевой инструмент разработки веб‑интерфейсов. Фронтенд‑разработчики используют язык для создания интерактивных приложений. С ростом проектов вырос и спрос на грамотную модульную организацию кода. Одним из базовых приёмов является экспорт и импорт функций между файлами: это упрощает повторное использование, тестирование и поддержку кода.
Что такое модуль JavaScript?
Модуль — это файл JavaScript, который экспортирует часть своей логики (переменные, функции, классы) и может быть импортирован в другие файлы. Определение в одну строку: модуль — это единица переиспользуемого кода.
Применение модулей упорядочивает проект, делает код более понятным и облегчает локализацию багов. Для использования модуля в браузере подключите скрипт с атрибутом type=”module”:
Существуют две семейства модулей:
- ECMAScript Modules (ESM) — современный стандарт, поддерживаемый большинством сред.
- CommonJS — старый формат (использовался в Node до широкого распространения ESM).
Дальше мы сосредоточимся на ESM.
Экспорт функций: что нужно знать
Экспорт позволяет сделать функции доступными из других файлов. В JavaScript функции — объекты первого класса, их удобно экспортировать и передавать.
Общие подходы к экспорту:
- Именованный экспорт (named export).
- Экспорт при объявлении (inline export).
- Экспорт по умолчанию (default export).
Пример функции в файле getPersonalDetails.js:
function getFullName(fullName){
fullName = prompt('What is your First Name');
console.log(fullName);
}Именованный экспорт (вне объявления):
export { getFullName };Экспорт при объявлении:
export function getFullName(fullName){
fullName = prompt('What is your First Name');
console.log(fullName);
}Экспорт нескольких функций:
export { getFullName, getEmail, getDob };Важно: именованные экспорты можно переименовывать при импорте. Это удобно для избегания конфликтов имён.
Экспорт по умолчанию
Экспорт по умолчанию используют, когда модуль предоставляет одно «главное» значение или функцию. Пример:
export default function getFullName(fullName){
// реализация
}Для default‑экспорта нельзя иметь более одного значения по умолчанию в модуле.
Импорт функций: базовые формы
Чтобы воспользоваться экспортированными значениями, импортируйте их в другом файле. Импорт требует, чтобы оригинальный файл уже экспортировал нужные сущности.
Импорт именованной функции:
import { getFullName } from './getPersonalDetails.js'Импорт нескольких функций:
import { getFullName, getEmail, getDob } from './getPersonalDetails.js'Импорт всех экспортов как объекта:
import * as personalDetailsModule from './getPersonalDetails.js'
personalDetailsModule.getFullName();Импорт default‑экспорта:
import fullName from './getPersonalDetails.js'Отличия:
- Для именованных импортов используются фигурные скобки.
- Default импорт не использует скобки; имя переменной может отличаться от имени функции в исходнике.
Практические примеры: структура проекта
Пример файловой структуры:
- src/
- utils/
- getPersonalDetails.js
- index.js (barrel)
- app.js
- utils/
getPersonalDetails.js:
export function getFullName(){ /* ... */ }
export function getEmail(){ /* ... */ }
export function getDob(){ /* ... */ }utils/index.js — barrel (файл‑«бочка») для удобного импорта:
export * from './getPersonalDetails.js'app.js:
import { getFullName, getEmail } from './utils'
getFullName();Barrel‑файлы упрощают импорт и помогают менять внутреннюю структуру без правки множества путей.
Советы по лучшим практикам
- Предпочитайте именованные экспорты в больших библиотеках. Они позволяют легче находить неиспользуемый код (tree‑shaking).
- Используйте default‑экспорт для «главной» сущности модуля (компонент, класс, фабрика).
- Держите модули маленькими и с одной ответственностью.
- Не делайте побочных эффектов при импорте: выполнение кода при загрузке модуля должно быть минимальным.
- Соглашение по именованию: файл с несколькими экспортами — множественное имя utils.js, с главным классом — имя класса.
Ошибки и отладка
Частые ошибки:
- Неправильный путь при импорте (относительные пути и расширение .js в браузере важны).
- Попытка импортировать default как именованный и наоборот.
- Дублирование имён при объединении нескольких импортов.
Отладка:
- В браузере смотрите в консоль сборщика/инструментов разработчика.
- В Node запускайте с включённым флагом ESM или используйте пакет type: “module” в package.json.
- Проверяйте ошибки синтаксиса импорта в линтере.
CommonJS против ESM: когда что использовать
- ESM — современный стандарт для модулей: статический анализ, поддержка tree‑shaking, синтаксис import/export.
- CommonJS (require/module.exports) всё ещё используется в некоторых проектах и пакетах.
При переходе с CommonJS на ESM обычно достаточно:
- заменить require на import;
- заменить module.exports на export default / named exports;
- обновить сборку/конфигурацию Node или сборщика.
Переход от CommonJS к ESM: краткий чек‑лист
- Установите в package.json “type”: “module” если требуется.
- Замените require на import в исходниках.
- Проверяйте сторонние зависимости: некоторые пакеты всё ещё CommonJS.
- Запустите тесты и сборку, исправьте пути и расширения.
Ментальные модели и эвристики
- Модуль = контракт: экспортируй только то, что нужен другим модулям.
- Каждый модуль — чёткая ответственность.
- Default ≈ «главная» вещь файла; named ≈ набор утилит.
Диаграмма принятия решения
flowchart TD
A[Нужно ли экспортировать одну основную сущность?] -->|Да| B[Используйте export default]
A -->|Нет| C[Экспортируйте именованные сущности]
C --> D[Нужен удобный централизованный импорт?]
D -->|Да| E[Добавьте barrel 'index.js' и export *]
D -->|Нет| F[Импортируйте напрямую по файлу]Роли и чек‑листы
Разработчик:
- Разбивать логику на модули с одной ответственностью.
- Писать тесты для экспортируемых функций.
- Избегать побочных эффектов.
Ревьюер кода:
- Проверить, что экспортируемые API минимальны.
- Убедиться в понятных именах и документации.
Тестировщик:
- Мокировать импортируемые модули при юнит‑тестировании.
- Проверить точки входа и поведение при неудачных данных.
Типичные паттерны и альтернативные подходы
- Barrel‑файлы для групп удобного импорта.
- Re‑export (переэкспорт): import {x} from ‘./a’; export {x};
- Динамический импорт (import()) для ленивой загрузки модулей.
Пример динамического импорта:
async function loadFeature(){
const mod = await import('./feature.js');
mod.init();
}Используйте динамический импорт для кода, который не нужен при первоначальной загрузке.
Критерии приёмки
- Модуль экспортирует только необходимые функции.
- Экспортированные функции документированы и покрыты тестами.
- Путь импорта корректен, сборка проходит без ошибок.
- При использовании default и named экспорта нет конфликтов имён.
Мини‑руководство по созданию модуля (SOP)
- Выделите одну ответственность.
- Реализуйте функции и покройте тестами.
- Выберите тип экспорта: named или default.
- Добавьте JSDoc/комментарии для публичных API.
- При необходимости сделайте barrel для группы модулей.
- Обновите импорты в проекте и запустите тесты.
Короткий глоссарий
- Модуль — файл с экспортируемыми сущностями.
- Named export — экспорт с именем (export { a }).
- Default export — основной экспорт модуля (export default …).
- Barrel — index.js, который реэкспортирует содержимое директории.
- Tree‑shaking — удаление неиспользуемого кода на этапе сборки.
Заключение
Экспорт и импорт функций — фундаментальный инструмент модульного программирования в JavaScript. Понимание тонкостей именованных и default‑экспортов, грамотная структура проекта и соглашения по именованию помогают создавать поддерживаемые и оптимизируемые приложения. Начните с простых правил: «одна ответственность на модуль», минимальный публичный API и тесты для экспортируемых функций. Эти практики значительно упрощают масштабирование проекта.
Важно: при миграции с CommonJS планируйте тестовый прогон и проверку сторонних зависимостей, а динамические импорты используйте для оптимизации загрузки.