Reputation: 11247
I don't know what this pattern is called, if I did I would look it up directly.
Mainly, how does this work? (This code is taken from Express.js)
exports = module.exports = createApplication;
I have seen similar patterns before where there is this type of reference variable chain ex:
x = y = z
I understand exports vs module.exports but looking at the pattern above it makes me question on how it actually works.
I go by the general rule of thumb that 'module.exports' is the real deal, and 'exports' is its helper, more on this here
Is the module pattern like this (without altering module.exports)?
exports = module.exports = {};
ex:
exports.name = 'hello'
results to
exports = module.exports = {name: 'hello'}
What happens when you change the reference on exports?
exports = {name: 'bob'}
Now when you add to exports, it will reference the `{name: 'bob'} and no longer have any ties with module.exports?
Upvotes: 5
Views: 949
Reputation: 4542
Your intuition is correct. I'll work from the bottom up:
Before running any file, Node.js wraps the entire script in an immediately-invoked function expression (IIFE):
(function (exports, require, module, __filename, __dirname) {
// ...script goes here...
});
This is how it introduces the module
and exports
variables into the scope; they're nothing more special than function arguments.
exports
The Node.js docs on module.exports
and the exports
alias are pretty helpful. To start out, module.exports
and the exports
variable both refer to the same empty object that was created by the module system.
If a module simply needs to export a plain old JavaScript object with some properties set, exports
is all that's needed:
exports.get = function(key) {
// ...
};
exports.set = function(key, value) {
// ...
};
When code require()
s this module, the result will look something like:
{
get: [Function],
set: [Function]
}
module.exports
However, Express exports a constructor function, createApplication
, as the root value. To export the function itself, rather than just assigning it to a property on the exported object, it must first replace the exported object entirely:
module.exports = createApplication;
Now, exports
hasn't been updated and still refers to the old object, whereas module.exports
is a reference to createApplication
. But if you keep reading, you'll notice that Express exports several other properties in addition to the constructor. While it would be sufficient to assign these to properties on the new value of module.exports
, it is shorter to reassign exports
so that it is again an alias to module.exports
, then assign those properties on exports
, which is equivalent to assigning them on module.exports
.
Thus, these examples are functionally equivalent:
module.exports = createApplication;
function createApplication() {
// ...
}
module.exports.application = proto;
module.exports.request = req;
module.exports.response = res;
But this one is less verbose:
exports = module.exports = createApplication;
function createApplication() {
// ...
}
exports.application = proto;
exports.request = req;
exports.response = res;
Either way, the result is the same, a function named createApplication
at the root with properties available on it:
{
[Function: createApplication]
application: [Object],
request: [Object],
response: [Object],
// ...a few other properties...
}
Upvotes: 5