module.exports vs exports in Node.js
I've found the following contract in a Node.js module:
module.exports = exports = nano = function database_module(cfg) {...}
I wonder what's the difference between module.exports
and exports
and why both are used here.
Solution 1:
Even though question has been answered and accepted long ago, i just want to share my 2 cents:
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;
So whatever you do just keep in mind that module.exports
and NOT exports
will be returned from your module when you're requiring that module from somewhere else.
So when you do something like:
exports.a = function() {
console.log("a");
}
exports.b = function() {
console.log("b");
}
You are adding 2 functions a
and b
to the object to which module.exports
points, so the typeof
the returning result will be an object
: { a: [Function], b: [Function] }
Of course, this is the same result you will get if you are using module.exports
in this example instead of exports
.
This is the case where you want your module.exports
to 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.exports
or exports
;(Remember again that module.exports
will be returned when you require something, not export
).
module.exports = function Something() {
console.log('bla bla');
}
Now typeof
returning 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.
However, using exports
you can't use something like:
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 point anymore to the object where module.exports
points, so there is not a relationship between exports
and module.exports
anymore. In this case module.exports
still points to the empty object {}
which will be returned.
The accepted answer from another topic should also help: Does JavaScript pass by reference?
Solution 2:
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.
module.js
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.
2nd least important reason
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.
Solution 3:
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.
Solution 4:
Initially,module.exports=exports
, and the require
function returns the object module.exports
refers to.
if we add property to the object, say exports.a=1
, then module.exports and exports still refer 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;
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. And if we require the file, it will not return the new object, since module.exports is not refer to the new object.
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.
Solution 5:
exports
and module.exports
are the same unless you reassign exports
within your module.
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:
module.exports = function() { ... }
If you simply assigned your function() { ... }
to exports
, you would be reassigning exports
to no longer point to module.exports
.
If you don't want to refer to your function by module.exports
every time, you can do:
module.exports = exports = function() { ... }
Notice that module.exports
is the left most argument.
Attaching properties to exports
is not the same since you are not reassigning it. That is why this works
exports.foo = function() { ... }