Модульная система Node.js позволяет разбивать код на отдельные файлы-модули, каждый из которых имеет собственную область видимости. Это решает проблему загрязнения глобального пространства имён и упрощает организацию кода.
Ключевые аспекты
module.exports — объект, который модуль экспортирует наружу
exports — сокращённая ссылка на module.exports
require() — функция для импорта модулей
Кэширование — модули загружаются и выполняются только один раз
Изоляция — переменные модуля недоступны извне без явного экспорта
Плюсы модульной системы
Инкапсуляция кода и данных
Повторное использование модулей
Чёткие зависимости между частями приложения
Упрощение тестирования
Минусы
Синхронная загрузка может блокировать выполнение
CommonJS не поддерживает tree-shaking
Циклические зависимости могут вызвать проблемы
Частые ошибки на собеседованиях
Путают exports и module.exports — присваивание exports = разрывает связь с module.exports
Забывают, что require кэширует модули
Не понимают разницу между CommonJS и ES Modules
Введение и проблематика
В раннем JavaScript весь код выполнялся в глобальной области видимости. Это приводило к конфликтам имён, сложности поддержки и невозможности повторного использования кода.
Node.js решил эту проблему, внедрив модульную систему CommonJS, где каждый файл — это отдельный модуль со своей областью видимости.
Модульная система Node.js появилась до стандартизации ES Modules и остаётся основной для серверного JavaScript.
Базовая теория
Что такое модуль?
Модуль в Node.js — это отдельный файл с JavaScript-кодом. Каждый модуль имеет:
Собственную область видимости (переменные не попадают в global)
Объект module с метаинформацией
Объект exports для экспорта функциональности
Функцию require для импорта других модулей
Структура модуля
Node.js оборачивает каждый модуль в функцию:
js
(function(exports, require, module, __filename, __dirname) {// Ваш код модуля здесь});
Это объясняет, почему переменные модуля изолированы и откуда берутся __dirname и __filename.
Практические примеры
Экспорт и импорт модулей
js
// math.jsfunctionadd(a, b) {return a + b;}functionsubtract(a, b) {return a - b;}// Экспортируем функцииmodule.exports.add = add;module.exports.subtract = subtract;// Или короче через exportsexports.multiply= (a, b) => a * b;
// a.jsconstb=require('./b');console.log('в a.js, b.done =',b.done);exports.done =true;// b.jsconsta=require('./a');console.log('в b.js, a.done =',a.done);exports.done =true;// При запуске a.js:// в b.js, a.done = undefined (a ещё не завершён!)// в a.js, b.done = true
Кэширование модулей
Node.js кэширует загруженные модули. Повторный require() возвращает тот же объект: