Каково назначение Node.js module.exports и как вы его используете - PullRequest
1362 голосов
/ 15 марта 2011

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

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

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

модуль

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

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

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

Ответы [ 11 ]

1545 голосов
/ 15 марта 2011

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 (обычно) является простым объектом, свойства которого могут быть доступны.

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


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

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

, за которым следует:

var m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName
211 голосов
/ 16 октября 2012

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

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

60 голосов
/ 20 января 2013

Обратите внимание, что механизм модуля NodeJS основан на CommonJS модулях, которые поддерживаются во многих других реализациях, таких как RequireJS , но также SproutCore , CouchDB , Ваканда , 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 (кэширование и циклические ссылки) )

33 голосов
/ 25 января 2013

Несколько вещей, о которых вы должны позаботиться, если назначите ссылку на новый объект для 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 голосов
/ 03 сентября 2014

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

enter image description here

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

18 голосов
/ 07 августа 2015

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

Помните, когда пишете модули

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

module exports diagram

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

9 голосов
/ 18 апреля 2015

ссылка на ссылку выглядит следующим образом:

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

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

есть что-то, что вынужно уделять больше внимания: не override export.

почему?

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

6 голосов
/ 27 июля 2016

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

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

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

Прежде чем я что-то напишу здесь, помните, что module.exports.additionTwo совпадает с exports.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');

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

3 голосов
/ 22 апреля 2016

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

Предположим, существует файл 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");
1 голос
/ 26 августа 2018

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

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

  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().
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...