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

1432

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

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

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

модуль

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

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

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

mrwooster
источник

Ответы:

1590

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

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

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

экспортировать (или «выставлять») функции внутренней области видимости myFunc1и myFunc2.

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

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

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

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


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

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

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

const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName
Альнитак
источник
119
Хороший ответ - мне кажется, что «разоблачения» были бы лучшим выбором терминологии, чем «экспорт»
UpTheCreek
2
@ApopheniaOverload - вы можете сделать "exports.func1, exports.func2 и т. Д.", Чтобы иметь несколько открытых методов из одного файла.
Hellatan
73
Модуль require должен иметь тип var m = require ('./ mymodule'); , с точкой и косой чертой. Таким образом, Node.js знает, что мы используем локальный модуль.
Gui Premonsa
7
Обязательно используйте синтаксис: require ('./ module_name'), потому что могут быть некоторые другие модули node.js с некоторым именем, и вместо того, чтобы выбирать свой собственный модуль, он подберет тот, который установлен с node.js
Сазид
3
@UpTheCreek Существует давняя традиция ссылаться на публичные символы, представленные модулем как «экспортируемые», которые существуют во многих системах программирования и десятилетиями. Это не был новый термин, придуманный разработчиками Node.
Марк Рид
218

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

Вы можете использовать оба 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 объяснена лучше в этом ответе здесь .

Джед Уотсон
источник
Как я могу позвонить Требовать некоторый модуль из другой папки, которая не имеет какой-либо корневой папки, как у меня?
Игал
@ user301639 вы можете использовать относительные пути для обхода иерархии файловой системы. requireначинается относительно папки, в которой вы выполняете node app.js. Я рекомендую опубликовать новый вопрос с явными примерами кода + структуры папок, чтобы получить более четкий ответ.
Джед Уотсон,
1
Мне пришлось настроить твой пример module.exports, чтобы он заработал. файл: var sayHello = require('./ex6_module.js'); console.log(sayHello());и модуль:module.exports = exports = function() { return "Hello World!"; }
Джейсон Лидон
1
Пример приращения оказался действительно хорошим, и я использовал его, чтобы освежить свой разум каждый раз, когда я перегружен тем, что я делаю с экспортом.
Манки
module.exports = exports = function(){...}2-й exportsэто просто переменная, верно? Другими словами, это может бытьmodule.exports = abc = function()
Jeb50
60

Обратите внимание, что механизм модуля 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 (кэширование и циклические ссылки) )

Александр Морго
источник
35

Несколько вещей, о которых вы должны позаботиться, если назначаете ссылку на новый объект 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() {}; 
Александр Морго
источник
29

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

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

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

Аниш
источник
18

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

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

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

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

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

ПГПИ
источник
9

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

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 является приватным для внешних пользователей.

qianjiahao
источник
6

При загрузке и установке 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');

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

Jumpman
источник
1
это экспорт или экспорт?
rudrasiva86
Спасибо за помощь :)
JumpMan
3

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

Предположим, есть файл 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");
Шантану Мадане
источник
Спасибо Если это помогло вам, пожалуйста, примите мой ответ :)
Shantanu Madane
1
Немного опоздал на вечеринку приятель :)
Бен Талиадорос
@ BenTaliadoros Я тоже думаю, что он опоздал, и я также думаю, что его объект anyVariable имеет много ошибок. строка выше метода sayHelloInSpanish не должна заканчиваться точкой с запятой (;), а функция sayHelloInSpanish = неверна. Все вещи не так с этим объектом. я отредактирую его ответ
божественный
1
редактирование отключено. Что еще alphadogg отредактировал в этом ответе?
божественное
Просто форматирование. Если это не какая-то сумасшедшая вещь о es6, с которой я не сталкивался, и я уверен, что это не так, то это вовсе не JS
Бен Талиадорос
2

Намерение:

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

Википедия

Я предполагаю, что становится трудно писать большие программы без модульного / многократно используемого кода. В 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 .

Moriarty
источник
1

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

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

  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()сразу.
Виллем ван дер Веен
источник
-3
let test = function() {
    return "Hello world"
};
exports.test = test;
Gtm
источник
4
Это тот же пример, что и в первом фрагменте принятого ответа ( return "Hello world"без разницы), но без каких-либо объяснений. Прежде чем ответить, убедитесь, что ваш ответ что-то добавит к теме.
Барбсан