Javascript node.js 中的 module.exports 与导出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7137397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:00:16  来源:igfitidea点击:

module.exports vs exports in Node.js

javascriptnode.jscommonjs

提问by Andreas K?berle

I've found the following contract in a Node.js module:

我在 Node.js 模块中找到了以下合同:

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

I wonder whats the different between module.exportsand exportsand why both are used here.

我不知道什么之间的不同module.exportsexports为什么都被用在这里。

采纳答案by Lime

Setting module.exportsallows the database_modulefunction to be called like a function when required. Simply setting exportswouldn't allow the function to be exported because node exports the object module.exportsreferences. The following code wouldn't allow the user to call the function.

设置module.exports允许在database_module时像函数一样调用函数required。简单的设置exports不允许导出函数,因为节点导出对象module.exports引用。以下代码不允许用户调用该函数。

module.js

模块.js

The following won't work.

以下将不起作用。

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

The following will work if module.exportsis set.

如果module.exports设置,以下将起作用。

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

console

安慰

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

Basically node.jsdoesn't export the object that exportscurrently references, but exports the properties of what exportsoriginally references. Although Node.jsdoes export the object module.exportsreferences, allowing you to call it like a function.

基本上node.js不会导出exports当前引用的对象,而是导出exports最初引用的对象的属性。尽管Node.js确实导出了对象module.exports引用,但允许您像调用函数一样调用它。



2nd least important reason

第二个最不重要的原因

They set both module.exportsand exportsto ensure exportsisn't referencing the prior exported object. By setting both you use exportsas a shorthand and avoid potential bugs later on down the road.

他们同时设置module.exportsexports以确保exports不引用先前导出的对象。通过将两者都设置exports为速记,并避免以后出现潜在的错误。

Using exports.prop = trueinstead of module.exports.prop = truesaves characters and avoids confusion.

使用exports.prop = true而不是module.exports.prop = true保存字符并避免混淆。

回答by Srle

Even though question has been answered and accepted long ago, i just want to share my 2 cents:

尽管很久以前就已经回答并接受了问题,但我只想分享我的 2 美分:

You can imagine that at the very beginning of your file there is something like (just for explanation):

你可以想象在你的文件的开头有这样的东西(只是为了解释):

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

enter image description here

在此处输入图片说明

So whatever you do just keep in mind that module.exportsand NOT exportswill be returned from your module when you're requiring that module from somewhere else.

因此,无论您做什么,请记住,当您从其他地方需要该模块时module.exports,不会exports从您的模块返回。

So when you do something like:

因此,当您执行以下操作时:

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

You are adding 2 function aand bto the object on which module.exportspoints too, so the typeofthe returning result will be an object: { a: [Function], b: [Function] }

您正在添加 2 个函数ab指向的对象module.exports,因此typeof返回结果将是一个object{ a: [Function], b: [Function] }

Of course, this is the same result you will get if you are using module.exportsin this example instead of exports.

当然,如果您module.exports在本示例中使用exports.

This is the case where you want your module.exportsto behave like a container of exported values. Whereas, if you only want to export a constructor function then there is something you should know about using module.exportsor exports;(Remember again that module.exportswill be returned when you require something, not export).

在这种情况下,您希望自己module.exports的行为像一个导出值的容器。然而,如果您只想导出一个构造函数,那么您应该了解使用module.exportsor 的一些知识exports;(再次记住,module.exports当您需要某些东西时将返回,而不是export)。

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

Now typeofreturning result is 'function'and you can require it and immediately invoke like:
var x = require('./file1.js')();because you overwrite the returning result to be a function.

现在typeof返回结果是'function',您可以要求它并立即调用:
var x = require('./file1.js')();因为您将返回结果覆盖为一个函数。

However, using exportsyou can't use something like:

但是,使用exports您不能使用以下内容:

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

Because with exports, the reference doesn't pointanymore to the object where module.exportspoints, so there is not a relationship between exportsand module.exportsanymore. In this case module.exportsstill points to the empty object {}which will be returned.

因为 with exports,引用不再指向指向的对象module.exports,所以exports和之间module.exports不再有关系。在这种情况下module.exports仍然指向{}将返回的空对象。

Accepted answer from another topic should also help: Does Javascript pass by reference?

从另一个主题接受的答案也应该有所帮助: Does Javascript pass by reference?

回答by Chandu

Basically the answer lies in what really happens when a module is required via requirestatement. Assuming this is the first time the module is being required.

基本上答案在于通过require语句需要模块时实际发生的情况。假设这是第一次需要该模块。

For example:

例如:

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

contents of file1.js:

file1.js 的内容:

module.exports = '123';

When the above statement is executed, a Moduleobject is created. Its constructor function is:

执行上述语句时,将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 = [];
}

As you see each module object has a property with name exports. This is what is eventually returned as part of require.

如您所见,每个模块对象都有一个 name 属性exports。这是最终作为require.

Next step of require is to wrap the contents of file1.js into an anonymous function like below:

require 的下一步是将 file1.js 的内容包装成一个匿名函数,如下所示:

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

And this anonymous function is invoked the following way, modulehere refers to the ModuleObject created earlier.

而这个匿名函数的调用方式如下,module这里指的Module是之前创建的Object。

(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");

As we can see inside the function, exportsformal argument refers to module.exports. In essence it's a convenience provided to the module programmer.

正如我们在函数内部看到的,exports形式参数指的是module.exports。从本质上讲,它为模块程序员提供了便利。

However this convenience need to be exercised with care. In any case if trying to assign a new object to exports ensure we do it this way.

但是,需要谨慎使用这种便利。在任何情况下,如果尝试将新对象分配给导出,请确保我们这样做。

exports = module.exports = {};

If we do it following way wrong way, module.exportswill still be pointing to the object created as part of module instance.

如果我们按照错误的方式进行操作module.exports仍将指向作为模块实例的一部分创建的对象。

exports = {};

As as result adding anything to the above exports object will have no effect to module.exports object and nothing will be exported or returned as part of require.

因此,向上述导出对象添加任何内容都不会对 module.exports 对象产生影响,并且不会作为 require 的一部分导出或返回任何内容。

回答by cameron

Initially,module.exports=exports, and the requirefunction returns the object module.exportsrefers to.

最初,module.exports=exportsrequire函数返回module.exports所指的对象。

if we add propertyto the object, say exports.a=1, then module.exports and exports stillrefer to the same object. So if we call require and assign the module to a variable, then the variable has a property a and its value is 1;

如果我们向对象添加属性,比如exports.a=1,那么 module.exports 和 exports仍然指向同一个对象。因此,如果我们调用 require 并将模块分配给一个变量,那么该变量具有一个属性 a,其值为 1;

But if we overrideone of them, for example, exports=function(){}, then they are differentnow: exports refers to a new object and module.exports refer to the original object. And if we require the file, it will not return the new object, since module.exports is not refer to the new object.

但是如果我们覆盖其中一个,例如,,exports=function(){}那么它们现在就不同了:exports 指的是一个新对象,module.exports 指的是原始对象。如果我们需要该文件,它不会返回新对象,因为 module.exports 不是指新对象。

For me, i will keep adding new property, or override both of them to a new object. Just override one is not right. And keep in mind that module.exportsis the real boss.

对我来说,我会不断添加新属性,或者将它们都覆盖到一个新对象。只覆盖一个是不对的。请记住,这module.exports是真正的老板。

回答by dustin.schultz

exportsand module.exportsare the same unless you reassign exportswithin your module.

exports并且module.exports是相同的,除非你重新分配exports你的模块中。

The easiest way to think about it, is to think that this line is implicitly at the top of every module.

考虑它的最简单方法是认为这一行隐含在每个模块的顶部。

var exports = module.exports = {};

If, within your module, you reassign exports, then you reassign it within your module and it no longer equals module.exports. This is why, if you want to export a function, you must do:

如果在您的模块内重新分配exports,则您在模块内重新分配它并且它不再等于module.exports。这就是为什么,如果你想导出一个函数,你必须这样做:

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

If you simply assigned your function() { ... }to exports, you would be reassigning exportsto no longer point to module.exports.

如果您只是将您的function() { ... }to分配给exports,您将重新分配exportsto 不再指向module.exports

If you don't want to refer to your function by module.exportsevery time, you can do:

如果你不想module.exports每次都引用你的函数,你可以这样做:

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

Notice that module.exportsis the left most argument.

请注意,这module.exports是最左边的参数。

Attaching properties to exportsis not the same since you are not reassigning it. That is why this works

附加属性exports是不一样的,因为你没有重新分配它。这就是为什么这有效

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

回答by superluminary

JavaScript passes objects by copy of a reference

JavaScript 通过引用的副本传递对象

It's a subtle difference to do with the way objects are passed by reference in JavaScript.

这与 JavaScript 中对象通过引用传递的方式有细微差别。

exportsand module.exportsboth point to the same object. exportsis a variable and module.exportsis an attribute of the module object.

exports并且module.exports都指向同一个对象。exports是一个变量,module.exports是模块对象的一个​​属性。

Say I write something like this:

说我写这样的东西:

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

exportsand module.exportsnow point to different objects. Modifying exports no longer modifies module.exports.

exportsmodule.exports现在指向不同的对象。修改导出不再修改 module.exports。

When the import function inspects module.exportsit gets {b:12}

当导入函数检查module.exports它时{b:12}

回答by Lyman Lai

I just make some test, it turns out that, inside nodejs's module code, it should something like this:

我只是做了一些测试,结果发现,在 nodejs 的模块代码中,它应该是这样的:

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

so:

所以:

1:

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:

2:

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

3: but, while in this case

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)

回答by Salar

Here is a good description written about node modules in node.js in actionbook from Manningpublication.
What ultimately gets exported in your application is module.exports.
exports
is set up simply as a global reference tomodule.exports , which initially is defined as an empty object that you can add properties to. So exports.myFuncis just shorthand for module.exports.myFunc.

As a result, if exportsis set to anything else, it breaks thereferencebetween module.exportsand exports . Becausemodule.exportsis what really gets exported, exportswill no longer work as expected—it doesn't referencemodule .exportsanymore. If you want to maintain that link, you can makemodule.exportsreferenceexports again as follows:

这是Manning出版的行动手册中关于node.js 中节点模块的一个很好的描述。 最终在您的应用程序中导出的是module.exports。出口设置仅仅作为一个全球性的参考module.exports,最初被定义为一个空的对象,您可以将属性添加。所以exports.myFunc是刚刚速记module.exports.myFunc。 因此,如果将导出设置为其他任何内容,则会破坏module.exportsexports之间 的引用。因为module.exports



是真正导出的内容,导出将不再按预期工作——它不再引用模块 .exports。如果您想保持该链接,您可以再次使module.exports引用导出,如下所示:

module.exports = exports = db;

回答by Cody

I went through some tests and I think this may shed some light on the subject...

我进行了一些测试,我认为这可能会对该主题有所了解......

app.js:

app.js

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

versions of /routes/index.js:

的版本/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] }"

I even added new files:

我什至添加了新文件:

./routes/index.js:

./routes/index.js

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

./routes/not-index.js:

./routes/not-index.js

exports = function fn(){};

./routes/user.js:

./routes/user.js

exports = function user(){};

We get the output "@routes {}"

我们得到输出“@routes {}”



./routes/index.js:

./routes/index.js

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

./routes/not-index.js:

./routes/not-index.js

exports = function fn(){};

./routes/user.js:

./routes/user.js

exports = function user(){};

We get the output "@routes { fn: {}, user: {} }"

我们得到输出“@routes { fn: {}, user: {} }”



./routes/index.js:

./routes/index.js

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

./routes/not-index.js:

./routes/not-index.js

exports.fn = function fn(){};

./routes/user.js:

./routes/user.js

exports.user = function user(){};

We get the output "@routes { user: [Function: user] }" If we change user.jsto { ThisLoadedLast: [Function: ThisLoadedLast] }, we get the output "@routes { ThisLoadedLast: [Function: ThisLoadedLast] }".

我们得到输出“@routes { user: [Function: user] }” 如果我们user.js改为{ ThisLoadedLast: [Function: ThisLoadedLast] },我们得到输出“@routes { ThisLoadedLast: [Function: ThisLoadedLast] }”。



But if we modify ./routes/index.js...

但是如果我们修改./routes/index.js...

./routes/index.js:

./routes/index.js

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

./routes/not-index.js:

./routes/not-index.js

exports.fn = function fn(){};

./routes/user.js:

./routes/user.js

exports.ThisLoadedLast = function ThisLoadedLast(){};

... we get "@routes { fn: { fn: [Function: fn] }, ThisLoadedLast: { ThisLoadedLast: [Function: ThisLoadedLast] } }"

...我们得到“@routes { fn: { fn: [Function: fn] }, ThisLoadedLast: { ThisLoadedLast: [Function: ThisLoadedLast] } }”

So I would suggest always use module.exportsin your module definitions.

所以我建议总是module.exports在你的模块定义中使用。

I don't completely understand what's going on internally with Node, but please comment if you can make more sense of this as I'm sure it helps.

我不完全了解 Node 内部发生了什么,但是如果您能对此有更多了解,请发表评论,因为我相信它会有所帮助。

-- Happy coding

-- 快乐编码

回答by Sudhir Srinivasan

I found this link useful to answer the above question.

我发现此链接对回答上述问题很有用。

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

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

To add to the other posts The module system in node does

添加到其他帖子节点中的模块系统确实

var exports = module.exports 

before executing your code. So when you want to exports = foo , you probably want to do module.exports = exports = foo but using exports.foo = foo should be fine

在执行你的代码之前。所以当你想导出 = foo 时,你可能想做 module.exports =exports = foo 但使用exports.foo = foo 应该没问题