Попытка разобраться, в чем различие между exports
и module.exports
, основанная на статье Understanding module.exports and exports in Node.js.
Что такое module.exports
и exports
в Node.js
Как web-разработчики, мы часто сталкиваемся с ситуацией, когда необходимо иметь дело с малознакомым кодом. И тогда сам собою возникает логичный вопрос - сколько времени мне потребуется для того, чтобы разобраться с чужим кодом и понять принцип его работы?
Типичный ответ на этот вопрос - ровно столько, чтобы начать самому
писать код; а затем вернуться к изучению этой темы позже, когда позволит
на это время. Ну что-же, как мне кажется, пришло время получше
разобраться с такими понятиями, как module.exports
и exports
в Node.js. Спешу поделиться с вами тем, что я узнал по этому вопросу.
Что такое модуль (module)
Основная концепция модуля заключается в том, что он инкапсулирует логически связанный между собой код в единый блок. Можно сказать иначе - создание модуля заключается в помещении всех взаимосвязанных между собой функций в один единый файл.
Для понимания вышесказанного лучше всего создать пример приложения под Node.js. Давайте создадим файл с именем greetings.js
, внутри которого размещены две функции:
sayHelloInEnglish = function () {
return Hello;
}
sayHelloInSpanish = function () {
return Hola;
}
Экспорт модуля
Польза от файла (модуля) greetings.js
(и функций, которые находятся в этом файле) появляется в том случае, когда файл greetings.js
можно использовать внутри других файлов (модулей).
Для достижения этого необходимо слегка изменить исходный код файла greetings.js
. Чтобы понять, что происходит на самом деле, в данном случае будем выполнять пошаговый процесс:
- представьте себе, что эта строка существует в качестве первой линии кода в
greetings.js
:
var exports = module.exports = {}
- видоизменим обе функции в файле
greetings.js
с помощью выраженияexports
таким образом, чтобы они были доступны для внешних файлов (модулей):
exports.sayHelloInEnglish = function () {
return Hello;
}
exports.sayHelloInSpanish = function () {
return Hola;
}
В приведенном выше коде можно было бы заменить выражение exports
на exports.module
и получить точно такой же результат.
Если этот момент кажется вам непонятным, то помните, что выражение exports
и выражение exports.module
ссылаются на один и тот же объект.
- это текущее значение выражения
module.exports
:
module.exports = {
sayHelloInEnglish = function () {
return Hello;
}
sayHelloInSpanish = function () {
return Hola;
}
}
Импортирование модуля
Давайте сделаем методы модуля greetings.js
общедоступными для другого файла (модуля) с именем main.js
. Этот процесс также разобьем пошагово для более лучшего понимания:
- в Node.js используется команда
require
для импортирования одного модуля в другой модуль:
var require = function(path) {
// ...
return module.exports;
};
- давайте подключим модуль
greetings.js
в модульmain.js
:
// main.js
var greeting = require(./greetings.js);
Приведенная выше строка кода равнозначна нижеследующему коду:
// main.js
var greeting = {
sayHelloInEnglish = function () {
return Hello;
}
sayHelloInSpanish = function () {
return Hola;
}
}
- теперь можно использовать функции модуля
greetings.js
внутри модуляmain.js
как методы объектаgreeting
:
// main.js
var greeting = require(./greetings.js);
// Hello
greeting.sayHelloInEnglish(Hello);
// Hola
greeting.sayHelloInSpanish(Hola);
Отличительные моменты
Команда require
возвращает объект, свойства и методы которого доступны другим внешним модулям при помощи команды module.exports
.
Нижеприведенный пример поможет разобраться в данном вопросе:
// greetings.js
// var exports = module.exports = {};
exports.sayHelloInEnglish = function () {
return Hello;
}
exports.sayHelloInSpanish = function () {
return Hola;
}
// Эта строка кода выполняет повторное переопределение,
module.exports = Bonjour;
Теперь сделаем подключение модуля greetings.js
в модуль main.js
:
// main.js
var greetings = require(./greetings.js)
На данный момент в нашем примере ничего не поменялось. В переменную greetings
помещается код, доступный из модуля greetings.js
. Не более того.
Однако, если мы попытаемся воспользоваться каким-либо из методов модуля greetings.js
- sayHelloInEnglish
или sayHelloInSpanish
,
то мы получим ошибку. Это произошло в следствие того, что было
произведено переопределение экспортируемой структуры модуля при помощи
команды module.exports
.
Другими словами, последней командой module.exports
экспортируется совсем другой модуль - Bonjour
, у которого другие свойства и методы. Происходит переопределение экспортируемого модуля и вызов метода sayHelloInEnglish
или sayHelloInSpanish
вызовет ошибку:
// main.js
// var greetings = require("./greetings.js");
/*
* TypeError: object Bonjour has no
* method sayHelloInEnglish
*/
greetings.sayHelloInEnglish();
/*
* TypeError: object Bonjour has no
* method sayHelloInSpanish
*/
greetings.sayHelloInSpanish();
Чтобы отследить ошибки при использовании модуля greetings
, можно вывести их в консоль:
// "Bonjour"
console.log(greetings);
Заключение
Импорт и экспорт модулей в Node.js является ежедневной задачей. Я
надеюсь, что благодаря этой статье стала ясна разница между командой exports
и командой module.exports
.
Более того, если у вас когда-либо произойдет ошибка при доступе к
общедоступным методам модуля в будущем, то я надеюсь, что у вас есть
лучшее понимание того, почему может возникнуть эти ошибки.
Заключение автора перевода
Если честно - прочитал статью и даже потрудился перевести ее, а вот разницы между exports
и module.exports
не заметил. Я хочу сказать, что автор этой статьи (как мне кажется) так
и не показал разницы между ними. Могу ошибаться, конечно и будут рад
комментариям.