Module.exports против экспорта в Node.js

Я нашел следующий контракт в модуле Node.js:

module.exports = exports = nano = function database_module(cfg) {...}

Интересно, в чем разница между module.exports и exports и почему оба используются здесь.

Ответ 1

Настройка module.exports позволяет функции database_module вызываться как функция, когда required. Просто установка exports не позволит функции экспортируется, потому что node экспортирует ссылки на объект module.exports. Следующий код не позволит пользователю вызывать функцию.

module.js

Следующие действия не будут работать.

exports = nano = function database_module(cfg) {return;}

Следующее будет работать, если установлено module.exports.

module.exports = exports = nano = function database_module(cfg) {return;}

консоль

var func = require('./module.js');
// the following line will **work** with module.exports
func();

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


Вторая по важности причина

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

Использование exports.prop = true вместо module.exports.prop = true сохраняет символы и позволяет избежать путаницы.

Ответ 2

Несмотря на то, что на вопрос уже дан ответ и он принят давно, я просто хочу поделиться своими 2 центами:

Вы можете представить, что в самом начале вашего файла есть что-то вроде (только для объяснения):

var module = new Module(...);
var exports = module.exports;

enter image description here

Поэтому, что бы вы ни делали, имейте в виду, что module.exports и НЕ exports будут возвращены из вашего модуля, когда вам потребуется этот модуль откуда-то еще.

Поэтому, когда вы делаете что-то вроде:

exports.a = function() {
    console.log("a");
}
exports.b = function() {
    console.log("b");
}

Вы добавляете две функции a и b к объекту, на который также указывает module.exports, поэтому typeof возвращающим результатом будет object: { a: [Function], b: [Function] }

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

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

module.exports = function Something() {
    console.log('bla bla');
}

Теперь typeof возвращает результат 'function', и вы можете потребовать его и немедленно вызвать как:
var x = require('./file1.js')(); потому что вы перезаписываете возвращаемый результат как функцию.

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

exports = function Something() {
    console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function

Поскольку с exports ссылка больше не указывает на объект, на который указывает module.exports, поэтому связь между exports и module.exports больше не существует. В этом случае module.exports по-прежнему указывает на пустой объект {}, который будет возвращен.

Принятый ответ из другой темы также должен помочь: Javascript передается по ссылке?

Ответ 3

В основном ответ заключается в том, что действительно происходит, когда модуль требуется с помощью инструкции require. Предполагая, что это первый раз, когда требуется модуль.

Например:

var x = require('file1.js');

содержимое файла file1.js:

module.exports = '123';

Когда выполняется вышеуказанный оператор, создается объект Module. Его конструкторская функция:

function Module(id, parent) {
    this.id = id;
    this.exports = {};
    this.parent = parent;
    if (parent && parent.children) {
        parent.children.push(this);
    }

    this.filename = null;
    this.loaded = false;
    this.children = [];
}

Как вы видите, каждый объект модуля имеет свойство с именем exports. Это то, что в конечном итоге возвращается как часть require.

Следующий шаг запроса - обернуть содержимое файла file1.js в анонимную функцию, как показано ниже:

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

И эта анонимная функция вызывается следующим образом: Module здесь ссылается на объект Module, созданный ранее.

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");

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

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

exports = module.exports = {};

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

exports = {};

В результате добавление чего-либо к указанному выше объекту экспорта не будет иметь эффекта для объекта module.exports, и ничто не будет экспортировано или возвращено как часть требуемого.

Ответ 4

Изначально module.exports=exports и функция require возвращает объект module.exports.

если мы добавим свойство к объекту, скажем exports.a=1, то module.exports и export еще относятся к одному и тому же объекту. Поэтому, если мы вызываем require и присваиваем модуль переменной, то переменная имеет свойство a, а ее значение равно 1;

Но если мы переопределяем один из них, например, exports=function(){}, то теперь они разные: экспорт относится к новому объекту и module.exports относятся к исходный объект. И если мы требуем файл, он не вернет новый объект, так как module.exports не относится к новому объекту.

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

Ответ 5

exports и module.exports совпадают, если вы не переназначаете exports в своем модуле.

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

var exports = module.exports = {};

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

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

Если вы просто назначили function() { ... } на exports, вы должны переназначить exports, чтобы больше не указывать на module.exports.

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

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

Обратите внимание, что module.exports является самым большим аргументом слева.

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

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

Ответ 6

JavaScript передает объекты по копии ссылки

Это тонкая разница в том, как объекты передаются по ссылке в JavaScript.

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

Скажем, я пишу что-то вроде этого:

exports = {a:1};
module.exports = {b:12};

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

Когда функция импорта проверяет module.exports она получает {b:12}

Ответ 7

Я просто делаю какой-то тест, оказывается, что внутри кода модуля nodejs он должен выглядеть примерно так:

var module.exports = {};
var exports = module.exports;

так:

1

exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.

2

exports.abc = function(){}; // works!
exports.efg = function(){}; // works!

3: но, в этом случае

module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)

Ответ 8

Вот хорошее описание, написанное о модулях node в node.js в действии из книги Manning.
То, что в конечном итоге экспортируется в ваше приложение, - это module.exports. Экспортировать. просто как глобальная ссылка на module.exports, которая изначально определяется как пустой объект, к которому вы можете добавить свойства. Таким образом, export.myFunc является просто сокращенным для module.exports.myFunc.

В результате, если export установлен на что-либо еще, он разбивает ссылку между module.exports и экспортирует. Потому что module.exports - это то, что действительно получает экспортировано, export больше не будет работать должным образом - он не ссылается на модуль .exports. Если вы хотите сохранить эту ссылку, вы можете сделать module.exports ссылка экспортирует снова следующим образом:

module.exports = exports = db;

Ответ 9

Я прошел некоторые тесты, и я думаю, что это может пролить свет на эту тему...

app.js:

var ...
  , routes = require('./routes')
  ...;
...
console.log('@routes', routes);
...

версии /routes/index.js:

exports = function fn(){}; // outputs "@routes {}"

exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

module.exports = function fn(){};  // outputs "@routes function fn(){}"

module.exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

Я даже добавил новые файлы:

./routes/index.js:

module.exports = require('./not-index.js');
module.exports = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Мы получаем вывод "@routes {}"


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Мы получаем вывод "@routes {fn: {}, user: {}}"


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.user = function user(){};

Мы получаем вывод "@routes {user: [Function: user]}" Если мы изменим user.js на { ThisLoadedLast: [Function: ThisLoadedLast] }, мы получим вывод "@routes {ThisLoadedLast: [Function: ThisLoadedLast]}".


Но если мы изменим ./routes/index.js...

./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.ThisLoadedLast = function ThisLoadedLast(){};

... мы получаем "@routes {fn: {fn: [Function: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}"

Поэтому я предлагаю всегда использовать module.exports в ваших определениях модулей.

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

- Счастливое кодирование

Ответ 10

Я нашел эту ссылку полезной для ответа на вышеуказанный вопрос.

http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/

Чтобы добавить к другим сообщениям Модульная система в node делает

var exports = module.exports 

перед выполнением кода. Поэтому, когда вы хотите экспортировать = foo, вы, вероятно, захотите сделать module.exports = exports = foo, но с помощью export.foo = foo должно быть хорошо

Ответ 11

Это показывает, как require() работает в своей простейшей форме, выдержка из Красноречивый JavaScript

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

Решение Предоставьте модули с другой переменной, module, которая является объектом, который имеет свойство exports. Это свойство первоначально указывает на пустой объект, созданный require, но может быть перезаписано другим значением, чтобы экспортировать что-то еще.

function require(name) {
  if (name in require.cache)
    return require.cache[name];
  var code = new Function("exports, module", readFile(name));
  var exports = {}, module = {exports: exports};
  code(exports, module);
  require.cache[name] = module.exports;
  return module.exports;
}
require.cache = Object.create(null);

Ответ 12

Вот результат

console.log("module:");
console.log(module);

console.log("exports:");
console.log(exports);

console.log("module.exports:");
console.log(module.exports);

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

также:

if(module.exports === exports){
    console.log("YES");
}else{
    console.log("NO");
}

//YES

Примечание: Спецификация CommonJS позволяет использовать только переменную экспорта для публичных пользователей. Таким образом, именованный шаблон экспорта является единственным, который действительно совместим с спецификацией CommonJS. Использование module.exports - это расширение, предоставляемое Node.js для поддержки более широкого диапазона шаблонов определения модуля.

Ответ 13

var a = {},md={};

//Во-первых, экспорт и module.exports указывают тот же пустой Object

exp = a;//exports =a;
md.exp = a;//module.exports = a;

exp.attr = "change";

console.log(md.exp);//{attr:"change"}

//Если вы укажете exp на другой объект, а не укажите его свойство для другого объекта. Md.exp будет пустым. Object {}

var a ={},md={};
exp =a;
md.exp =a;

exp = function(){ console.log('Do nothing...'); };

console.log(md.exp); //{}

Ответ 14

Из docs

Переменная экспорта доступна в пределах области уровня файла модуля и ей присваивается значение module.exports перед оценкой модуля.

Он позволяет использовать ярлык, так что module.exports.f =... может быть написано более кратко как export.f =.... Однако помните, что, как и любая переменная, if новое значение присваивается экспорту, оно больше не привязано к module.exports:

Это просто переменная, указывающая на module.exports.

Ответ 15

"Если вы хотите, чтобы корень вашего экспорта модуля являлся функцией (например, конструктором), или если вы хотите экспортировать полный объект в одно задание, а не создавать его по одному свойству за раз, назначьте его модулю. экспорт вместо экспорта". - http://nodejs.org/api/modules.html

Ответ 16

1.exports → использовать как утилиту singleton
2. module-exports → использовать как логические объекты, такие как сервис, модель и т.д.

Ответ 17

Создайте один модуль двумя способами:

Один из способов

var aa = {
    a: () => {return 'a'},
    b: () => {return 'b'}
}

module.exports = aa;

Второй способ

exports.a = () => {return 'a';}
exports.b = () => {return 'b';}

И вот как require() будет интегрировать модуль.

Первый способ:

function require(){
    module.exports = {};
    var exports = module.exports;

    var aa = {
        a: () => {return 'a'},
        b: () => {return 'b'}
    }
    module.exports = aa;

    return module.exports;
}

Второй способ

function require(){
    module.exports = {};
    var exports = module.exports;

    exports.a = () => {return 'a';}
    exports.b = () => {return 'b';}

    return module.exports;
}

Ответ 18

почему оба используются здесь

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

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

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


module.exports против exports

До тех пор, пока вы не переназначить module.exports или exports (и вместо того, чтобы добавлять значения в объект они оба относятся к), у вас не будет никаких проблем и может безопасно использовать exports более кратким.

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

Установка exports в не-объект не имеет особого смысла, поскольку вам нужно будет установить module.exports = exports в конце, чтобы иметь возможность использовать его в других файлах.

let module = { exports: {} };
let exports = module.exports;

exports.msg = 'hi';
console.log(module.exports === exports); // true

exports = 'yo';
console.log(module.exports === exports); // false

exports = module.exports;
console.log(module.exports === exports); // true

module.exports = 'hello';
console.log(module.exports === exports); // false

module.exports = exports;
console.log(module.exports === exports); // true

Зачем присваивать функции module.exports функции?

Более краткий! Сравните, насколько короче второй пример:

helloWorld1.js: module.exports.hello =() => console.log('hello world');

app1.js: let sayHello = require('./helloWorld1'); sayHello.hello;//hello world let sayHello = require('./helloWorld1'); sayHello.hello;//hello world

helloWorld2.js: module.exports =() => console.log('hello world');

app2.js: let sayHello = require('./helloWorld2'); sayHello;//hello world let sayHello = require('./helloWorld2'); sayHello;//hello world

Ответ 19

enter image description here

Каждый созданный вами файл является модулем. Модуль является объектом. У него есть свойство exports: {} которое по умолчанию является пустым объектом.

Вы можете создавать функции/промежуточное программное обеспечение и добавлять к этому пустому объекту экспорта, например exports.findById() => {... } затем require любом месте вашего приложения и использовать...

Контроллеры/user.js

exports.findById = () => {
    //  do something
}

Требовать в route.js использовать:

const {findyId} = './controllers/user'

Ответ 20

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

Любое свойство, которое вы добавляете к объекту module.exports будет доступно, когда ваш модуль используется в другом модуле с помощью оператора require. exports - это ярлык, доступный для того же. Например:

module.exports.add = (a, b) => a+b

эквивалентно написанию:

exports.add = (a, b) => a+b

Так что все в порядке, если вы не назначаете новое значение для переменной exports. Когда вы делаете что-то вроде этого:

exports = (a, b) => a+b 

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

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

module.exports = exports = (a, b) => a+b

Сайт Node.js имеет очень хорошее объяснение этого.

Ответ 21

in node Файл js module.js используется для запуска системы module.load.когда всякий раз, когда node выполняет файл, он переносит содержимое вашего js файла следующим образом

'(function (exports, require, module, __filename, __dirname) {',+
     //your js file content
 '\n});'

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

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

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

посмотрите следующий код

скопируйте этот код в b.js

console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();

скопируйте этот код в a.js

exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}

теперь выполняется с помощью node

это вывод

module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true

export is [object Object]

object.keys из foo: name is function() {console.log('функция для экспорта модулей')} функция экспорта модулей

теперь удалите прокомментированную строку в a.js и прокомментируйте строку над этой строкой и удалите последнюю строку b.js и запустите.

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

помните

используйте module.exports и только если вы хотите получить функцию при использовании ключевого слова require. в приведенном выше примере мы var foo = require (a.js); вы можете видеть, что мы можем вызвать foo как функцию;

вот как объясняет документация node "Объект экспорта создается системой модулей. Иногда это неприемлемо, многие хотят, чтобы их модуль был экземпляром некоторого класса. Для этого назначьте желаемый объект экспорта в module.exports."

Ответ 22

  • Оба module.exports и exports указывают на тот же function database_module(cfg) {...}.

    1| var a, b;
    2| a = b = function() { console.log("Old"); };
    3|     b = function() { console.log("New"); };
    4|
    5| a(); // "Old"
    6| b(); // "New"
    

    Вы можете изменить b в строке 3 на a, выход будет обратным. Вывод:

    a и b независимы.

  • Итак, module.exports = exports = nano = function database_module(cfg) {...} эквивалентно:

    var f = function database_module(cfg) {...};
    module.exports = f;
    exports = f;
    

    Предполагалось, что выше module.js, что требуется foo.js. Преимущества module.exports = exports = nano = function database_module(cfg) {...} теперь понятны:

    • В foo.js, так как module.exports есть require('./module.js'):

      var output = require('./modules.js')();
      
    • В moduls.js: вы можете использовать exports вместо module.exports.

Итак, вы будете счастливы, если оба exports и module.exports указывают на одно и то же.