Какова цель Node.js module.exports и как вы его используете?

Какова цель Node.js module.exports и как вы его используете?

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

Согласно документации Node.js:

модуль

Ссылка на текущий module, Особенно module.exports совпадает с объектом экспорта. Увидеть src/node.js для дополнительной информации.

Но это не очень помогает.

Что именно делает module.exports делать, и что будет простой пример?

13 ответов

Решение

module.exports это объект, который на самом деле возвращается в результате require вызов.

exports переменная изначально установлена ​​на этот же объект (т.е. это сокращенное "псевдоним"), поэтому в коде модуля вы обычно пишете что-то вроде этого:

var myFunc1 = function() { ... };
var myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;

экспортировать (или "выставить") функции внутренней области видимости myFunc1 а также myFunc2,

И в коде вызова вы будете использовать:

var m = require('./mymodule');
m.myFunc1();

где последняя строка показывает, как результат require обычно это простой объект, свойства которого могут быть доступны.

NB: если перезаписать exports тогда это больше не будет относиться к module.exports, Поэтому, если вы хотите назначить новый объект (или ссылку на функцию) exports тогда вы должны также назначить этот новый объект module.exports


Стоит отметить, что имя добавлено в exports Объект не обязательно должен совпадать с внутренним именем модуля для значения, которое вы добавляете, поэтому вы можете иметь:

var myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required

с последующим:

var m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName

На это уже был дан ответ, но я хотел бы добавить некоторые уточнения...

Вы можете использовать оба exports а также module.exports импортировать код в ваше приложение следующим образом:

var mycode = require('./path/to/mycode');

Основной вариант использования, который вы увидите (например, в примере кода ExpressJS), заключается в том, что вы устанавливаете свойства на exports объект в файле.js, который затем импортируется с помощью require()

Таким образом, в простом примере подсчета вы могли бы иметь:

(counter.js):

var count = 1;

exports.increment = function() {
    count++;
};

exports.getCount = function() {
    return count;
};

... затем в вашем приложении (web.js или в любом другом файле.js):

var counting = require('./counter.js');

console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2

Проще говоря, вы можете рассматривать требуемые файлы как функции, которые возвращают один объект, и вы можете добавить свойства (строки, числа, массивы, функции, что угодно) к объекту, который возвращается, установив их в exports,

Иногда вам захочется вернуть объект из require() Вызывать функцию, которую вы можете вызвать, а не просто объект со свойствами. В этом случае вам также необходимо установить module.exports, как это:

(sayhello.js):

module.exports = exports = function() {
    console.log("Hello World!");
};

(app.js):

var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"

Разница между export и module.exports объяснена лучше в этом ответе здесь.

Обратите внимание, что механизм модуля NodeJS основан на модулях CommonJS, которые поддерживаются во многих других реализациях, таких как RequireJS, но также SproutCore, CouchDB, Wakanda, OrientDB, ArangoDB, RingoJS, TeaJS, SilkJS, curl.js или даже Adobe Photoshop (через PSLib).). Вы можете найти полный список известных реализаций здесь.

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

Еще одна особенность NodeJS - это когда вы назначаете ссылку на новый объект exports вместо того, чтобы просто добавлять свойства и методы к нему, как в последнем примере, представленном Джедом Уотсоном в этой теме. Я бы лично не одобрял эту практику, так как это нарушает круговую ссылочную поддержку механизма модулей CommonJS. Это тогда не поддерживается всеми реализациями, и пример Jed должен быть написан таким образом (или подобным), чтобы обеспечить более универсальный модуль:

(sayhello.js):

exports.run = function() {
    console.log("Hello World!");
}

(app.js):

var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"

Или используя функции ES6

(sayhello.js):

Object.assign(exports, {
    // Put all your public API here
    sayhello() {
        console.log("Hello World!");
    }
});

(app.js):

const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"

PS: Похоже, что Appcelerator также реализует модули CommonJS, но без поддержки циклических ссылок (см.: модули Appcelerator и CommonJS (кэширование и циклические ссылки))

Несколько вещей, о которых вы должны позаботиться, если назначаете ссылку на новый объект exports и / или modules.exports:

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

Это очевидно, но если вы добавляете экспортированный метод в начале существующего модуля, убедитесь, что собственный экспортируемый объект не ссылается на другой объект в конце

exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object

module.exports.method3 = function () {}; // exposed with method1 & method2

var otherAPI = {
    // some properties and/or methods
}

exports = otherAPI; // replace the original API (works also with module.exports)

2. В случае, если один из exports или же module.exports ссылаются на новое значение, они больше не ссылаются на один и тот же объект

exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object

// method added to the original exports object which not exposed any more
module.exports.method3 = function () {}; 

3. Хитрое следствие. Если вы измените ссылку на оба exports а также module.exportsсложно сказать, какой API выставлен (похоже module.exports выигрывает)

// override the original exported object
module.exports = function AConstructor() {};

// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {}; 

Свойство module.exports или объект экспорта позволяет модулю выбирать, что должно быть передано приложению

введите описание изображения здесь

У меня есть видео на module_export, доступное здесь

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

Помните при написании модулей

  • Загрузка модулей кэшируется, только первоначальный вызов оценивает JavaScript.
  • Внутри модуля можно использовать локальные переменные и функции, не все нужно экспортировать.
  • module.exports объект также доступен как exports стенографии. Но при возврате единственной функции всегда используйте module.exports,

схема экспорта модуля

Согласно: "Модули Часть 2 - Написание модулей".

Ссылочная ссылка выглядит так:

exports = module.exports = function(){
    //....
}

свойства exports или же module.exports, такие как функции или переменные, будут выставлены снаружи

есть что-то, на что вы должны обратить больше внимания: не override экспорт.

Зачем?

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

хороший пример:

exports.name = 'william';

exports.getName = function(){
   console.log(this.name);
}

плохой пример:

exports = 'william';

exports = function(){
     //...
}

Если вы просто хотите выставить только одну функцию или переменную, вот так:

// test.js
var name = 'william';

module.exports = function(){
    console.log(name);
}   

// index.js
var test = require('./test');
test();

этот модуль предоставляет только одну функцию, а свойство name является приватным для внешних пользователей.

При загрузке и установке node.js есть несколько модулей по умолчанию или существующих в файле node.js, таких как http, sys и т. Д.

Поскольку они уже находятся в файле node.js, когда мы хотим использовать эти модули, нам, в основном, нравятся модули импорта, но почему? потому что они уже присутствуют в node.js. Импортировать все равно, что брать их из node.js и помещать в свою программу. А потом с их помощью.

В то время как Exports с точностью до наоборот, вы создаете нужный модуль, скажем, модуль extension.js и помещаете этот модуль в node.js, вы делаете это путем его экспорта.

Прежде, чем я что-то напишу здесь, помните, что module.exports.additionTwo такой же, как export.additionTwo

Да, так вот почему нам нравится

exports.additionTwo = function(x)
{return x+2;};

Будьте осторожны с путем

Допустим, вы создали модуль дополнения.js,

exports.additionTwo = function(x){
return x + 2;
};

Когда вы запускаете это в командной строке NODE.JS:

node
var run = require('addition.js');

Это будет ошибка, сказав

Ошибка: не удается найти модуль дополнения.js

Это связано с тем, что процесс node.js не может добавить дополнение.js, поскольку мы не упомянули путь. Итак, мы можем установить путь с помощью NODE_PATH

set NODE_PATH = path/to/your/additon.js

Теперь это должно успешно работать без ошибок!

Еще одна вещь, вы также можете запустить файл дополнения.js, не устанавливая NODE_PATH, обратно в командную строку nodejs:

node
var run = require('./addition.js');

Поскольку мы предоставляем здесь путь, говоря, что он находится в текущем каталоге ./ это также должно работать успешно.

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

Предположим, есть файл Hello.js, который включает две функции

sayHelloInEnglish = function() {
  return "Hello";
};
sayHelloInSpanish = function() {
  return "Hola";
};

Мы пишем функцию только тогда, когда утилита кода является более чем одним вызовом.

Предположим, мы хотим увеличить полезность функции до другого файла, скажем, World.js, в этом случае экспорт файла начинается с изображения, которое можно получить с помощью module.exports.

Вы можете просто экспортировать обе функции по приведенному ниже коду

var anyVariable={
 sayHelloInEnglish = function() {
      return "Hello";
    };
  sayHelloInSpanish = function() {
      return "Hola";
    }; 
}
module.export=anyVariable;

Теперь вам просто нужно указать имя файла в порядке World.js, чтобы использовать эти функции.

var world= require("./hello.js");

Намерение:

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

Википедия

Я полагаю, что становится трудно писать большие программы без модульного / многократно используемого кода. В nodejs мы можем создавать модульные программы, используя module.exports определить, что мы выставляем и составляем нашу программу с require,

Попробуйте этот пример:

fileLog.js

function log(string) { require('fs').appendFileSync('log.txt',string); }

module.exports = log;

stdoutLog.js

function log(string) { console.log(string); }

module.exports = log;

program.js

const log = require('./stdoutLog.js')

log('hello world!');

выполнять

$ node program.js

Привет, мир!

Теперь попробуйте обменяться ./stdoutLog.js на ./fileLog.js.

Модули ECMAScript — 2022 г.

Начиная с Node 14.0 модули ECMAScript больше не являются экспериментальными, и вы можете использовать их вместо классических модулей Node CommonJS.

Модули ECMAScript являются официальным стандартным форматом для упаковки кода JavaScript для повторного использования. Модули определяются с использованием различных операторов импорта и экспорта.

Вы можете определить модуль ES, который экспортирует функцию:

      // my-fun.mjs
function myFun(num) {
  // do something
}

export { myFun };

Затем вы можете импортировать экспортированную функцию из my-fun.mjs:

      // app.mjs
import { myFun } from './my-fun.mjs';

myFun();

.mjsявляется расширением по умолчанию для модулей Node.js ECMAScript. Но вы можете настроить расширение модулей по умолчанию для поиска при разрешении модулей с помощью package.json поле "тип" или--input-typeфлаг в CLI.

Последние версии Node.js полностью поддерживают модули ECMAScript и CommonJS. Кроме того, он обеспечивает взаимодействие между ними.

Модули ECMAScript и CommonJS имеют много различий, но самое существенное отличие в этом вопросе заключается в том, что больше нет requireс, не более exports, больше не надо module.exports

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

История выпусков модулей ECMAScript

| Релиз | Изменения || ------- | ------- || v15.3.0, v14.17.0, v12.22.0 | Внедрение стабилизированных модулей || v14.13.0, v12.20.0 | Поддержка обнаружения именованных экспортов CommonJS || v14.0.0, v13.14.0, v12.20.0 | Предупреждение об удалении экспериментальных модулей || v13.2.0, v12.17.0 | Для загрузки модулей ECMAScript больше не требуется флаг командной строки || v12.0.0 | Добавлена ​​поддержка модулей ES с использованием расширения файла .js через поле «тип» package.json || v8.5.0 | Добавлена ​​начальная реализация модулей ES | Вы можете найти все журналы изменений в репозитории Node.js.

Какова цель модульной системы?

Это выполняет следующие вещи:

  1. Сохраняет наши файлы от вздутия до действительно больших размеров. Наличие файлов, содержащих, например, 5000 строк кода, обычно очень сложно в процессе разработки.
  2. Обеспечивает разделение интересов. Разделение нашего кода на несколько файлов позволяет нам иметь соответствующие имена файлов для каждого файла. Таким образом, мы можем легко определить, что делает каждый модуль и где его найти (при условии, что мы создали логическую структуру каталогов, которая по-прежнему остается вашей ответственностью).

Наличие модулей облегчает поиск определенных частей кода, что делает наш код более понятным.

Как это работает?

NodejS использует модульную систему CommomJS, которая работает следующим образом:

  1. Если файл хочет экспортировать что-то, он должен объявить это, используя module.export синтаксис
  2. Если файл хочет импортировать что-то, он должен объявить это, используя require('file') синтаксис

Пример:

test1.js

const test2 = require('./test2');    // returns the module.exports object of a file

test2.Func1(); // logs func1
test2.Func2(); // logs func2

test2.js

module.exports.Func1 = () => {console.log('func1')};

exports.Func2 = () => {console.log('func2')};

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

  1. Модули кэшируются. Когда вы загружаете один и тот же модуль в 2 разных файла, модуль должен быть загружен только один раз. Второй раз require() вызывается на том же модуле, который извлекается из кеша.
  2. Модули загружаются синхронно. Такое поведение требуется, если оно было асинхронным, мы не смогли бы получить доступ к объекту, полученному из require() сразу.
let test = function() {
    return "Hello world"
};
exports.test = test;
Другие вопросы по тегам