В программировании модули являются автономными функциональными единицами, которые могут совместно использоваться в проектах. Они облегчают нашу жизнь как разработчиков, поскольку мы можем использовать их для расширения наших приложений функциональностью, которую нам не приходилось писать самим. Они также позволяют нам организовывать и отделять наш код, что приводит к приложениям, которые легче понять, отлаживать и поддерживать.
В этой статье я рассмотрю, как работать с модулями в Node.js, сосредоточив внимание на том, как их экспортировать и использовать.
Различные форматы модулей
Поскольку в JavaScript изначально не было понятия модулей, со временем появилось множество конкурирующих форматов. Вот список основных из которых следует знать:
- Формат определения асинхронного модуля (AMD) используется в браузерах и использует функцию
define
- Формат CommonJS (CJS) используется в Node.js и использует
require
module.exports
Экосистема npm построена на этом формате. - Формат модуля ES (ESM) . Начиная с ES6 (ES2015), JavaScript поддерживает собственный формат модулей. Он использует ключевое слово
export
- Формат System.register был разработан для поддержки модулей ES6 в ES5.
- Формат универсального определения модуля (UMD) можно использовать как в браузере, так и в Node.js. Это полезно, когда модуль должен быть импортирован несколькими различными загрузчиками модулей.
Обратите внимание, что эта статья посвящена исключительно формату CommonJS , стандарту Node.js. Если вы хотите ознакомиться с любым из других форматов, я рекомендую эту статью автора SitePoint Юргена Ван де Моера.
Требуется модуль
Node.js поставляется с набором встроенных модулей, которые мы можем использовать в нашем коде без необходимости их установки. Для этого нам потребуется модуль с ключевым словом import
Затем его можно использовать для вызова любых методов, предоставляемых модулем.
Например, чтобы вывести список содержимого каталога, вы можете использовать модуль файловой системы и метод require
readdir
Обратите внимание, что в CommonJS модули загружаются синхронно и обрабатываются в порядке их появления.
Создание и экспорт модуля
Теперь давайте посмотрим, как создать наш собственный модуль и экспортировать его для использования в других местах нашей программы. Начните с создания файла const fs = require('fs');
const folderPath = '/home/jim/Desktop/';
fs.readdir(folderPath, (err, files) => {
files.forEach(file => {
console.log(file);
});
});
user.js
Теперь создайте файл const getName = () => {
return 'Jim';
};
exports.getName = getName;
index.js
Запустите программу, используя const user = require('./user');
console.log(`User: ${user.getName()}`);
node index.js
Так что здесь произошло? Что ж, если вы посмотрите на файл User: Jim
user.js
getName
Затем в файле exports
Также обратите внимание, что в операторе index.js
require
Также обратите внимание, что нет необходимости добавлять расширение файла.
Экспорт нескольких методов и значений
Мы можем экспортировать несколько методов и значений одним и тем же способом:
./
И в const getName = () => {
return 'Jim';
};
const getLocation = () => {
return ‘Munich’;
};
const dateOfBirth = ‘12.01.1982’;
exports.getName = getName;
exports.getLocation = getLocation;
exports.dob = dateOfBirth;
index.js
Код выше производит это:
const user = require('./user');
console.log(
`${user.getName()} lives in ${user.getLocation()} and was born on ${user.dob}.`
);
Обратите внимание, что имя, которое мы даем экспортированной переменной Jim lives in Munich and was born on 12.01.1982.
dateOfBirth
Оно не должно совпадать с исходным именем переменной.
Вариации в синтаксисе
Я должен также упомянуть, что можно экспортировать методы и значения по мере необходимости, а не только в конце файла.
Например:
dob
А благодаря назначению по деструктуризации мы можем выбрать то, что хотим импортировать:
exports.getName = () => {
return 'Jim';
};
exports.getLocation = () => {
return 'Munich';
};
exports.dob = '12.01.1982';
Как и следовало ожидать, эти журналы:
const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);
Экспорт значения по умолчанию
В приведенном выше примере мы экспортируем функции и значения по отдельности. Это удобно для вспомогательных функций, которые могут понадобиться во всем приложении, но когда у вас есть модуль, который экспортирует только одну вещь, более распространенным является использование Jim was born on 12.01.1982.
module.exports
И в class User {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
}
getUserStats() {
return `
Name: ${this.name}
Age: ${this.age}
Email: ${this.email}
`;
}
}
module.exports = User;
index.js
Код выше регистрирует это:
const User = require('./user');
const jim = new User('Jim', 37, '[email protected]');
console.log(jim.getUserStats());
В чем разница между Name: Jim
Age: 37
Email: [email protected]
module.exports
Age: 37
Email: [email protected]
В своих путешествиях через Интернет вы можете встретить следующий синтаксис:
exports
Здесь мы присваиваем функции и значения, которые мы хотим module.exports = {
getName: () => {
return 'Jim';
},
getLocation: () => {
return ‘Munich’;
},
dob: ‘12.01.1982’,
};
exports
module
Это регистрирует следующее:
const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);
Так в чем же разница между Jim was born on 12.01.1982.
module.exports
Является ли один удобный псевдоним для другого?
Ну, вроде, но не совсем …
Чтобы проиллюстрировать, что я имею в виду, давайте изменим код в exports
index.js
module
console.log(module);
Это производит:
Module {
id: '.',
exports: {},
parent: null,
filename: '/home/jim/Desktop/index.js',
loaded: false,
children: [],
paths:
[ '/home/jim/Desktop/node_modules',
'/home/jim/node_modules',
'/home/node_modules',
'/node_modules' ] }
Как видите, module
exports
Давайте добавим что-то к этому:
// index.js
exports.foo = 'foo';
console.log(module);
Это выводит:
Module {
id: '.',
exports: { foo: 'foo' },
...
Назначение свойств для exports
module.exports
Это потому, что (изначально, по крайней мере) exports
module.exports
Так какой из них я должен использовать?
Так как module.exports
exports
Например:
exports.foo = 'foo';
module.exports.bar = 'bar';
Этот код приведет к тому, что экспортированный объект модуля будет { foo: 'foo', bar: 'bar' }
Однако есть одна оговорка. Все, что вы назначаете для module.exports
Итак, возьмем следующее:
exports.foo = 'foo';
module.exports = () => { console.log('bar'); };
Это приведет только к экспорту анонимной функции. Переменная foo
Если вы хотите узнать больше о разнице, я рекомендую эту статью .
Вывод
Модули стали неотъемлемой частью экосистемы JavaScript, что позволяет нам создавать большие программы из небольших частей. Я надеюсь, что эта статья дала вам хорошее представление о работе с ними в Node.js, а также о демистификации их синтаксиса.
Если у вас есть какие-либо вопросы или комментарии, не стесняйтесь заходить на форумы SitePoint, чтобы начать обсуждение.