Mar
Mar

Reputation: 1606

Nodejs exports and module.exports: Why do we need exports anyway?

As I read through the some of the answers on another question on this topic:

I (guess) understand what exports and module.exports are and how they can be used!

What I don't understand is why do we need exports anyway since we can perfectly work things out with using only module.exports. Besides, If I conceive it good: exports has potential to create bugs.

For example:

// feature.js
function Person(name) {
    this.name = name;
    this.greet = function() {
        console.log('Hi, my name is ' + this.name);
    }
}
module.exports = Person;

// app.js
var Person = require(./feature);

var Aron = new Person('Aron');
Aron.greet(); // Hi, my name is Aron

You can simply break this working version with using exports:

exports = Person; // wont' work   
exports.Person = Person; // still won't work (until you resolve it as new Person.Person('Aron') or ..require(..).Person) Which is not readable..

Why do we have exports anyway? Can someone explain to me the benefits of using exports instead of module.exports?

Thanks advance!

Upvotes: 2

Views: 101

Answers (1)

jfriend00
jfriend00

Reputation: 707308

If you are just adding properties to module.exports or to exports, then you can modify either one and get the same result. This is because both module.exports and exports initially point to the exact same object. So, if you modify one, the other is pointing at the same object so the change will be seen in either one. exports is apparently just provided as a typing shortcut so you don't have to refer to module.exports.

So, this is perfectly safe:

exports.foo = 123;

Or

module.exports.foo = 123;

Both create exactly the same result and are both safe as they each just assign a property to the same object.

But, if you are creating and assigning a whole new exports object, then you MUST assign that object to module.exports. Assigning it only to exports will not do you any good.

The syntax:

exports = module.exports = {foo: 1};

Makes absolutely sure that no mistakes are made in this regard and is probably why it is recommended.

What I don't understand is why do we need exports anyway since we can perfectly work things out with using only module.exports.

As long as your code NEVER uses exports, you can just use module.exports and never worry about exports. You do not NEED exports. It was likely provided as a convenience, but as you have figured out that convenience can lead to bugs if misused.

Why do we have exports anyway? Can someone explain to me the benefits of using exports instead of module.exports?

exports was probably just provided as a typing convenience. The only benefit to using exports over module.exports is a little less typing and perhaps a teeny performance difference as there is one less property lookup. Personally I just pretend exports isn't there and I never use it. I logically think of module.exports as the real location for exports so I just assign or modify there and there is never have a problem doing it that way.


Here's the longer explanation.

When a module is initialized, it is wrapped inside a function that looks like this:

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

This is where the definition of module and exports come from. By default, module.exports === exports when this function is first executed and your module code starts to run. But, exports is just a convenience here. The real exports are in module.exports. So, if you just do this:

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

That ends up not doing anything because module.exports will not be affected at all and that's where the real exports are. But, if you do this:

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

Then, the real exports are indeed modified and your module will work properly, but as soon as you execute module.exports = {foo: 123};, you've made module.exports point to new object and it will now point at a different object than exports points to. So, for total safety, some people recommend you do this:

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

Then, both exports and module.exports always point at the same object.


If you NEVER use exports by itself, then you don't ever need to assign anything to it and you can just do this:

module.exports = {foo: 123};

And, there will be no issues at all. But, you have to make sure that no code actually uses just exports if you've changed the object that module.exports points to.

Upvotes: 6

Related Questions