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

725

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

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

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

Андреас Кёберле
источник
81
Большой ресурс: hacksparrow.com/node-js-exports-vs-module-exports.html ^ _ ^
Нафтали, он же Нил,
6
Обновлена ​​ссылка «для потомков»: nodejs.org/docs/latest/api/modules.html#modules_module_exports
Zeke
8
Это все о ссылках. Думайте об экспорте как о объекте локальной переменной, указывающем на module.exports. Если вы перезаписываете значение export, тогда вы теряете ссылку на module.exports, а module.exports - это то, что вы выставляете как открытый интерфейс.
Габриэль Ламас
14
Краткое резюме: оба exportsи module.exportsуказывают на один и тот же объект, если вы не переназначите один. И в конце module.exportsвозвращается. Поэтому, если вы переназначены exportsна функцию, то не ожидайте функцию, поскольку она не будет возвращена. Однако, если бы вы назначили функцию, подобную этой, exports.func = function...то получившаяся вещь имела бы свойство func со значением функции. Потому что вы добавили свойство к объекту, который exportsуказывает на ..
Мухаммед Умер

Ответы:

426

Настройка module.exportsпозволяет database_moduleвызывать функцию как функцию, когда required. Простая настройка exportsне позволит экспортировать функцию, потому что узел экспортирует 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ссылки на объекты , позволяя вам вызывать их как функции.


2-я наименее важная причина

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

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

Лайм
источник
8
@ajostergaard: Это просто название библиотеки, из которой был взят пример ОП. В модуле он позволяет автору писать такие вещи, как nano.version = '3.3'вместо module.exports.version = '3.3', что читается немного яснее. (Обратите внимание, что nanoэто локальная переменная, объявленная
незадолго
3
@ лайм - спасибо - я рад, что это в значительной степени не имеет значения, потому что если бы это было не так, это означало бы, что я полностью все неправильно понял. : - | :)
ostergaard
Привет, Лайм, это довольно старый ответ, но я надеюсь, ты сможешь кое-что прояснить. Если бы я должен был установить, module.exportsно нет exports , мой код все еще работал бы? Спасибо за любую помощь!
Асад Саидуддин
1
@Asad Да, функция будет экспортироваться правильно, если вы установилиmodule.exports
Lime
@Liam спасибо за ценный ответ. еще несколько запросов - при входе в server.js, каковы ожидаемые значения module.exports и exports? ожидается, что module.exports будет нулевым, а для экспорта задан пустой объект? Это наследие или есть какой-то действительный вариант использования, чтобы когда-либо указывать export и module.exports на два разных объекта?
Сушил
504

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

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

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

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

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

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

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

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

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

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

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 передается по ссылке?

Srle
источник
2
Хорошее объяснение, но я до сих пор не понимаю, как вы можете полностью пропустить module.exportsмодуль, например, в этом npmпакете: github.com/tj/consolidate.js/blob/master/lib/consolidate.js
CodyBugstein
4
@ Я объясню здесь: JavaScript передается по ссылке? exports.a = function(){}; works, exports = function(){} doesn't work
Cirpo
29
оооо, наконец, этот ответ объясняет это. По сути, экспорт относится к объекту, к которому вы можете добавить свойства, но если вы переназначаете его для функционирования, вы больше не присоединяете свойство к этому исходному объекту. Теперь экспорт ссылается на функцию, в то время как module.exports все еще указывает на этот объект, и поскольку это то, что возвращается. Вы можете сказать, что экспорт был в основном мусором.
Мухаммед Умер
5
Итак, какой смысл использовать exports? Почему бы просто не использовать всегда, module.exportsесли это просто переназначение переменной? Кажется, смущает меня.
jedd.ahyoung
1
@ jedd.ahyoung Менее громоздко писать exports.somethingвместоmodule.exports.something
Srle
209

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

Следующий шаг 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, и ничего не будет экспортировано или возвращено как часть require.

Chandu
источник
8
Потерял меня здесьexports = module.exports = {};
Гигантский Лось
2
Я думаю, что это должен быть лучший ответ, он объясняет, почему func()не в ответе @ Уильяма!
горлица
2
Я не вижу никакого преимущества exports = module.exports = app;в последней строке кода. Похоже, что module.exportsбудет экспортировано, и мы никогда не будем использовать exports, потому что опять-таки это в последней строке кода. Итак, почему бы нам просто не добавитьmodule.exports = app;
иврают
80

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

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

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

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

Cameron
источник
1
Да, это действительно реальный ответ. Это сжато и понятно. Другие могут быть правы, но полны причудливых терминов и не сосредоточены именно на ответе на этот вопрос.
Khoa
Это, безусловно, самый ясный ответ! Если вы хотите добавить его в закладки, это точная ссылка: stackoverflow.com/questions/7137397/…
lambdarookie
57

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

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

var exports = module.exports = {};

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

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

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

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

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

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

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

exports.foo = function() { ... }
dustin.schultz
источник
9
Это было проще всего понять из всех ответов!
Адарш Кончади
2
Красиво
1
Простой и легкий способ понять эту функцию.
FilipeCanatto
27

JavaScript передает объекты путем копирования ссылки

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

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

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

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

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

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

superluminary
источник
6
Лучший ответ imho!
Мистер Эй Джей
1
"JavaScript проходит по ссылке" - No.
xehpuk
13

Я просто провожу некоторый тест, и получается, что внутри кода модуля 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)
Лиман Лай
источник
Лиман, поэтому module.exportsявляется своего рода «реального дела» , что узел уходит из , но в какой - то момент вам нужно добавить все , exportsчтобы , module.exportsесли вы не будете использовать exports.namespace(случай 2 выше), в этом случае , кажется, как Узел пробежал extends(module.exports, exports);добавление всех «пространств имен» из exportsк module.exportsобъекту? Другими словами, если вы используете, exportsто вы, вероятно, хотите установить свойства для него?
Коди
11

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

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

module.exports = exports = db;
Салар
источник
8

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

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

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

Cody
источник
Я думаю, что они излишне сложны и запутаны. Он должен быть прозрачным и интуитивно понятным.
ngungo
Согласен. Это может быть полезно для пространства имен при некоторых обстоятельствах, но, как правило, ничего не собирается делать или ломать.
Коди
4

Это показывает, как require()работает в простейшем виде, взято из Eloquent 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);
onmyway133
источник
Мне пришлось воссоздать это в Node и протестировать несколько вещей, пока я не получил, я сосу. По сути, внутренняя функция, созданная для модуля, даже не возвращает объект экспорта. Таким образом, объект «export» фактически не переназначается в модуле, например, если вы попытаетесь написать export = «теперь это строка». Объект существует только как ссылка. Это поведение, которое я не думаю, что до сих пор правильно понял.
Даниэльгормли
4

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

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 позволяет использовать переменную export только для предоставления открытых членов. Следовательно, именованный шаблон экспорта является единственным, который действительно совместим со спецификацией CommonJS. Использование module.exports - это расширение, предоставляемое Node.js для поддержки более широкого диапазона шаблонов определения модулей.

Серкан
источник
4
var a = {},md={};

// Во-первых, export и module.exports указывают на один и тот же пустой объект

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); //{}
Энсон Хван
источник
4

Из документов

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

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

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

ANewGuyInTown
источник
4

Я нашел эту ссылку полезной, чтобы ответить на поставленный выше вопрос.

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

Добавить к другим сообщениям Система модулей в узле делает

var exports = module.exports 

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

Судхир Шринивасан
источник
git link не работает
Джесси Хэттабо
Ссылка теперь исправлена.
Павел Гольчицкий
3

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

madKakoo
источник
3

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

Любое свойство, которое вы добавляете к module.exports объекту, будет доступно, когда ваш модуль используется в другом модуле using 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 имеет очень хорошее объяснение этого.

Джастин Патроз Варед
источник
2

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

РИВ
источник
2

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

В одну сторону

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;
}
Дмитрий Сергеев
источник
2

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

Я считаю , что они просто хотят , чтобы быть ясно , что 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

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

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

JBallin
источник
2

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

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

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

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

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

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

const {findyId} = './controllers/user'
Райан Dhungel
источник
2

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

 (function(exports, require, module, __filename, __dirname) {

 })()

Обратите внимание, что первый параметр exports- это пустой объект, а третий параметр module- это объект со многими свойствами, и одно из свойств называется exports. Это то, что exportsисходит и что module.exportsисходит. Первый является переменным объектом, а второй является свойством moduleобъекта.

Внутри модуля Node.js автоматически делает это в начале: module.exports = exportsи в конечном итоге возвращает module.exports.

Таким образом, вы можете видеть, что если вы переназначите какое-то значение exports, это не будет иметь никакого эффекта module.exports. (Просто потому, что exportsуказывает на другой новый объект, но module.exportsвсе еще содержит старый exports)

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

exports = { a: 1 }
console.log(module.exports) // {}

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

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

exports.a = 1;
module.exports.b = 2;
console.log(module.exports) // { a: 1, b: 2 }

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

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

exports.a = 1;
module.exports = {
  hello: () => console.log('hello')
}
console.log(module.exports) // { hello: () => console.log('hello')}
qinmu2127
источник
0

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

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

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

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

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

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

скопируйте этот код в 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');}

Теперь запустить с использованием узла

это выход

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

экспорт является [объект объекта]

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

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

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

помнишь

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

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

sidias
источник
0
  1. Оба 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независимы.

  2. Так 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указываете на одно и то же.

Льется
источник