I\'ve found the following contract in a Node.js module:
module.exports = exports = nano = function database_module(cfg) {...}
I wonder what
I just make some test, it turns out that, inside nodejs's module code, it should something like this:
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)
From the docs
The exports variable is available within a module's file-level scope, and is assigned the value of module.exports before the module is evaluated.
It allows a shortcut, so that module.exports.f = ... can be written more succinctly as exports.f = .... However, be aware that like any variable, if a new value is assigned to exports, it is no longer bound to module.exports:
It is just a variable pointing to module.exports.
module.exports
and exports
both point to the same object before the module is evaluated.
Any property you add to the module.exports
object will be available when your module is used in another module using require
statement. exports
is a shortcut made available for the same thing. For instance:
module.exports.add = (a, b) => a+b
is equivalent to writing:
exports.add = (a, b) => a+b
So it is okay as long as you do not assign a new value to exports
variable. When you do something like this:
exports = (a, b) => a+b
as you are assigning a new value to exports
it no longer has reference to the exported object and thus will remain local to your module.
If you are planning to assign a new value to module.exports
rather than adding new properties to the initial object made available, you should probably consider doing as given below:
module.exports = exports = (a, b) => a+b
Node.js website has a very good explanation of this.
Each file you create is a module. module is an object. It has property called exports : {}
which is empty object by default.
you can create functions/middlewares and add to this empty exports object such as exports.findById() => { ... }
then require
anywhere in your app and use...
controllers/user.js
exports.findById = () => {
// do something
}
require in routes.js to use:
const {findyId} = './controllers/user'
Setting module.exports
allows the database_module
function to be called like a function when required
. Simply setting exports
wouldn't allow the function to be
exported because node exports the object module.exports
references. The following code wouldn't allow the user to call the function.
The following won't work.
exports = nano = function database_module(cfg) {return;}
The following will work if module.exports
is set.
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.js doesn't export the object that exports
currently references, but exports the properties of what exports
originally references. Although Node.js does export the object module.exports
references, allowing you to call it like a function.
They set both module.exports
and exports
to ensure exports
isn't referencing the prior exported object. By setting both you use exports
as a shorthand and avoid potential bugs later on down the road.
Using exports.prop = true
instead of module.exports.prop = true
saves characters and avoids confusion.
Basically the answer lies in what really happens when a module is required via require
statement. Assuming this is the first time the module is being required.
For example:
var x = require('file1.js');
contents of file1.js:
module.exports = '123';
When the above statement is executed, a Module
object is created. 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
. This is what is eventually returned as part of require
.
Next step of require is to wrap the contents of file1.js into an anonymous function like below:
(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.
(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
. 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.
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.