Статьи

Понимание module.exports и экспорта в Node.js

В программировании модули являются автономными функциональными единицами, которые могут совместно использоваться в проектах. Они облегчают нашу жизнь как разработчиков, поскольку мы можем использовать их для расширения наших приложений функциональностью, которую нам не приходилось писать самим. Они также позволяют нам организовывать и отделять наш код, что приводит к приложениям, которые легче понять, отлаживать и поддерживать.

В этой статье я рассмотрю, как работать с модулями в Node.js, сосредоточив внимание на том, как их экспортировать и использовать.

Различные форматы модулей

Поскольку в JavaScript изначально не было понятия модулей, со временем появилось множество конкурирующих форматов. Вот список основных из которых следует знать:

  • Формат определения асинхронного модуля (AMD) используется в браузерах и использует функцию define
  • Формат CommonJS (CJS) используется в Node.js и использует requiremodule.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.jsgetName
Затем в файле exports Также обратите внимание, что в операторе index.jsrequire Также обратите внимание, что нет необходимости добавлять расширение файла.

Экспорт нескольких методов и значений

Мы можем экспортировать несколько методов и значений одним и тем же способом:

 ./

И в 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, 'jim@example.com');

console.log(jim.getUserStats());

В чем разница между Name: Jim
Age: 37
Email: jim@example.com
module.exports

В своих путешествиях через Интернет вы можете встретить следующий синтаксис:

 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
Является ли один удобный псевдоним для другого?

Ну, вроде, но не совсем …

Чтобы проиллюстрировать, что я имею в виду, давайте изменим код в exportsindex.jsmodule

 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' ] }

Как видите, moduleexports Давайте добавим что-то к этому:

 // index.js
exports.foo = 'foo';
console.log(module);

Это выводит:

 Module {
  id: '.',
  exports: { foo: 'foo' },
  ...

Назначение свойств для exportsmodule.exports Это потому, что (изначально, по крайней мере) exportsmodule.exports

Так какой из них я должен использовать?

Так как module.exportsexports Например:

 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, чтобы начать обсуждение.