Что такое модуль?

Модуль - это отдельный программный файл в Node.js. При создании модуля его можно классифицировать как группировку всех связанных функций в файл.

getYear = function() {
   return new Date().getFullYear();
}
getMonth = function() {
   return new Date().getMonth();
}

Назначение модуля

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

Наиболее распространенные форматы модулей

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

  • Формат CommonJS (CJS) используется в Node.js и использует require и module.exports для определения зависимостей и модулей. Экосистема npm построена на этом формате.
  • Формат ES Module (ESM). Начиная с ES6 (ES2015), JavaScript поддерживает собственный формат модуля. Он использует ключевое слово export для экспорта общедоступного API модуля и ключевое слово import для его импорта.

В этой статье мы поговорим о формате CommonJS.

Требуется модуль

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

вы можете использовать модуль файловой системы и его readdir метод:

const fs = require('fs');
const folderPath = '/home/jim/Desktop/';
fs.readdir(folderPath, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});

Обратите внимание, что в CommonJS модули загружаются синхронно и обрабатываются в порядке их появления.

Создание и экспорт модуля

создать наш собственный модуль и экспортировать его для использования в другом месте нашей программы.

// user.js
const getName = () => {
  return 'Jim';
};
exports.getName = getName;

Другой модуль - index.js.

// index.js
const user = require('./user');
console.log(`User: ${user.getName()}`);

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

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

// user.js
const getName = () => {
  return 'Jim';
};
const getLocation = () => {
  return 'Munich';
};
const dateOfBirth = '12.01.1982';
exports.getName = getName;
exports.getLocation = getLocation;
exports.dob = dateOfBirth;

indxe.js

// index.js
const user = require('./user');
console.log(
  `${user.getName()} lives in ${user.getLocation()} and was born on ${user.dob}.`);

Обратите внимание, что имя, которое мы даем экспортируемой 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}.`);

Экспорт значения по умолчанию

когда у вас есть модуль, который экспортирует только одну вещь, чаще используется module.exports, но наверняка вы можете использовать только `exports`:

// user.js
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());

В чем разница между module.exports и exports?

создайте файл index.js и запустите его с помощью node

console.log(module);

выход:

Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/yaapa/projects/hacksparrow.com/run.js',
  loaded: false,
  children: [],
  paths:
   [ '/Users/yaapa/projects/hacksparrow.com/node_modules',
     '/Users/yaapa/projects/node_modules',
     '/Users/yaapa/node_modules',
     '/Users/node_modules',
     '/node_modules' ] }

Похоже, module - это контекстная ссылка на файл, который вы только что запустили.

Вы заметили, что у него есть свойство exports? Это пустой объект. Здесь вы определяете «импортируемые» объекты вашего модуля.

Теперь отредактируйте index.js и снова запустите его:

// index.js
exports.firstName = "Ibrahim";
exports.lastName = "AlRayyan";
Module {
  id: '.',
  exports: { firstName: 'Ibrahim', lastName: 'AlRayyan' },
  ...

Вы можете видеть, что присвоение свойств объекту exports добавило эти свойства к modules.exports.

Это потому, что exports - это ссылка на modules.exports.

Вы можете подтвердить это с помощью следующего кода:

// index.js
exports.firstName = "Ibrahim";
console.log(exports === module.exports);
console.log(module.exports);

Результатом будет:

true
{ firstName: 'Ibrahim' }

Давайте теперь объясним настоящую разницу между ними, записав некоторые коды в два отдельных файла.

Я буду использовать два файла user.js и index.js, где index.js никогда не изменится:

// index.js
const fullName = require('./user');
console.log(fullName);
  1. Использует onlyexports в экспортируемом (исходном) файле → user.js:
// user.js
const lastName = "AlRayyan";
const firstName = "Ibrahim";
exports.firstName = firstName;
exports.lastName = lastName;

Результатом будет:

{ firstName: 'Ibrahim', lastName: 'AlRayyan' }
  1. Использует exports и module.exports в одном исходном файле:
// user.js
const lastName = "AlRayyan";
const firstName = "Ibrahim";
module.exports = {x: "x"};
exports.lastName = lastName;

Результатом будет:

{ x: 'x' }

Таким образом, использование module.exports и exports в одном файле отменяет значение exports. И не следует использовать их оба в одном файле или модуле.

Другие полезные вещи, которые нужно знать

Когда функция require () вызывается для одного и того же модуля в нескольких файлах, модуль необходимо загрузить только один раз. В следующий раз, когда для того же модуля вызывается функция require (), она извлекается из кеша.
Функция require () загружает модули синхронно. Предположим, он загружает модули асинхронно, мы не можем получить доступ к объектам должным образом. Таким образом, требуется синхронное поведение при переходе от одного файла к другому.

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

Ссылки

  1. Https://www.sitepoint.com/understanding-module-exports-exports-node-js/
  2. Https://www.hacksparrow.com/nodejs/exports-vs-module-exports.html
  3. Https://www.agiratech.com/blog/understanding-module-exports-and-exports-in-node-js/