本文翻译自:module.exports vs exports in Node.js
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.exports
and exports
and why both are used here. 我不知道什么之间的不同module.exports
和exports
,为什么都被用在这里。
参考:https://stackoom.com/question/TwlJ/Node-js中的module-exports与export
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 因此,当您要exports = foo时,您可能想要执行module.exports = exports = foo,但是使用exports.foo = foo应该没问题。
Basically the answer lies in what really happens when a module is required via require
statement. 基本上,答案在于通过require
语句require
模块时实际发生的情况。 Assuming this is the first time the module is being required. 假设这是第一次需要该模块。
For example: 例如:
var x = require('file1.js');
contents of file1.js: file1.js的内容:
module.exports = '123';
When the above statement is executed, a Module
object is created. 执行以上语句后,将创建一个Module
对象。 Its constructor function is: 其构造函数为:
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
. 如您所见,每个模块对象都有一个名称为exports
的属性。 This is what is eventually returned as part of require
. 这最终是作为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, module
here refers to the Module
Object created earlier. 而这个匿名函数被调用下面的方式, 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");
As we can see inside the function, exports
formal argument refers to module.exports
. 正如我们在函数内部看到的那样, exports
形式参数指向module.exports
。 In essence it's a convenience provided to the module programmer. 从本质上讲,这是为模块程序员提供的便利。
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.exports
will 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的一部分导出或返回。
Initially, module.exports=exports
, and the require
function returns the object module.exports
refers to. 最初, module.exports=exports
, require
函数返回对象module.exports
引用的对象。
if we add property to the object, say exports.a=1
, then module.exports and exports still refer to the same object. 如果我们向对象添加属性 ,例如export.a exports.a=1
,则module.exports和export 仍引用同一对象。 So if we call require and assign the module to a variable, then the variable has a property a and its value is 1; 因此,如果我们调用require并将模块分配给变量,则该变量具有a属性,其值为1;
But if we override one of them, for example, exports=function(){}
, then they are different now: exports refers to a new object and module.exports refer to the original object. 但是,如果我们覆盖其中一个,例如export exports=function(){}
,那么它们现在就不同了:export指向新对象,而module.exports指向原始对象。 And if we require the file, it will not return the new object, since module.exports is not refer to the new object. 如果我们需要该文件,它将不会返回新对象,因为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.exports
is the real boss. 请记住, module.exports
是真正的老板。
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: 所以:
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.
exports.abc = function(){}; // works!
exports.efg = function(){}; // works!
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)
in node js module.js file is use to run the module.load system.every time when node execute a file it wrap your js file content as follow 节点js中的module.js文件用于运行module.load system。每次节点执行文件时,它都会将您的js文件内容包装如下
'(function (exports, require, module, __filename, __dirname) {',+
//your js file content
'\n});'
because of this wrapping inside ur js source code you can access exports,require,module,etc.. this approach is used because there is no other way to get functionalities wrote in on js file to another. 由于此包装在ur js源代码中,因此您可以访问export,require,module等。之所以使用此方法,是因为没有其他方法可以将在js文件中写入的功能复制到另一个文件中。
then node execute this wrapped function using c++. 然后节点使用c ++执行此包装函数。 at that moment exports object that passed into this function will be filled. 届时将填充传递到此函数的导出对象。
you can see inside this function parameters exports and module. 您可以在此函数中看到参数导出和模块。 actually exports is a public member of module constructor function. 实际上,exports是模块构造函数的公共成员。
look at following code 看下面的代码
copy this code into b.js 将此代码复制到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();
copy this code to a.js 将此代码复制到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');}
now run using node 现在使用节点运行
module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true
object.keys of foo: name is function (){console.log('function to module exports')} function to module exports foo的object.keys:名称为function(){console.log('function to module导出')} function to module export
now remove the commented line in a.js and comment the line above that line and remove the last line of b.js and run. 现在删除a.js中的注释行,并注释该行上方的行,并删除b.js的最后一行并运行。
in javascript world you cannot reassign object that passed as parameter but you can change function's public member when object of that function set as a parameter to another function 在javascript世界中,您不能重新分配作为参数传递的对象,但是当该函数的对象设置为另一个函数的参数时,可以更改该函数的公共成员
use module.exports on and only if you wants to get a function when you use require keyword . 仅在要使用require关键字时要获得功能时,才使用module.exports。 in above example we var foo = require(a.js); 在上面的示例中,我们var foo = require(a.js); you can see we can call foo as a function; 您可以看到我们可以将foo作为函数调用;
this is how node documentation explain it "The exports object is created by the Module system. Sometimes this is not acceptable, many want their module to be an instance of some class. To do this assign the desired export object to module.exports." 这就是节点文档的解释方式:“导出对象是由Module系统创建的。有时这是不可接受的,许多人希望其模块成为某个类的实例。为此,请将所需的导出对象分配给module.exports。”