javascript tutorial - [Solved-5 Solutions] Module.exports vs exports in node.js - javascript - java script - javascript array



Problem:

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

module.exports = exports = nano = function database_module(cfg) {...}
click below button to copy the code. By JavaScript tutorial team
  • We wonder whats the different between module.exports and exports and why both are used here

Solution 1:

The following won't work.

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

click below button to copy the code. By JavaScript tutorial team

The following will work if module.exports is set.

module.exports = exports = nano = function database_module(cfg) {return;}
click below button to copy the code. By JavaScript tutorial team

console

var func = require('./module.js');
// the following line will **work** with module.exports
func();
click below button to copy the code. By JavaScript tutorial team
  • 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 we 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 we 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 2:

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');
click below button to copy the code. By JavaScript tutorial team

contents of file1.js:

module.exports = '123';
click below button to copy the code. By JavaScript tutorial team

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 = [];
}
click below button to copy the code. By JavaScript tutorial team
  • As we 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;
});
click below button to copy the code. By JavaScript tutorial team

And this anonymous function is invoked the following way, module here refers to the ModuleObject 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");
click below button to copy the code. By JavaScript tutorial team
  • 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 = {};
click below button to copy the code. By JavaScript tutorial team

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

exports = {};
click below button to copy the code. By JavaScript tutorial team

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 3:

  • Initially, module.exports=exports , and the require function returns the object module.exportsrefers 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, we 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 4:

JavaScript passes by reference.It's a subtle difference to do with the way objects are passed by reference in JavaScript. exports and module.exports both point to the same object. exports is a variable and module.exports is an attribute of the module object.

Say we write something like this:

exports = {a:1};
module.exports = {b:12};
click below button to copy the code. By JavaScript tutorial team

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

Solution 5:

  • Here is a good description written about node modules in node.js in action book from Manningpublication.
  • What ultimately gets exported in our application is module.exports.
  • exports is set up simply as a global reference to module.exports , which initially is defined as an empty object that we can add properties to. So exports.myFunc is just shorthand for module.exports.myFunc.
  • As a result, if exports is set to anything else, it breaks the reference between module.exports and exports . Because module.exports is what really gets exported, exports will no longer work as expected-it doesn’t reference module .exports anymore. If we want to maintain that link, we can make module.exports reference exports again as follows:
module.exports = exports = db;
click below button to copy the code. By JavaScript tutorial team

Related Searches to javascript tutorial - Module.exports vs exports in node.js