Source Link of the article:
http://www.sitepoint.com/understanding-module-exports-exports-node-js/
As developers, we often face situations where we need to use unfamiliar code. A question will arise during these moments. How much time should I invest in understanding the code that I’m about to use? A typical answer is learn enough to start coding; then explore that topic further when time permits. Well, the time has come to gain a better understanding of
module.exports
and exports
in Node.js. Here’s what I have learned.What is a Module
A module encapsulates related code into a single unit of code. When creating a module, this can be interpreted as moving all related functions into a file. Let’s illustrate this point with an example involving an application built with Node.js. Imagine that we created a file called
greetings.js
and it contains the following two functions:
1
2
3
4
5
6
7
8
| // greetings.js sayHelloInEnglish = function () { return "Hello" ; }; sayHelloInSpanish = function () { return "Hola" ; }; |
Exporting a Module
The utility of
greetings.js
increases when its encapsulated code can be utilized in other files. So let’s refactor greetings.js
to achieve this goal. To comprehend what is actually happening, we can follow a three-step process:
1) Imagine that this line of code exists as the first line of code in
greetings.js
:
1
2
| // greetings.js var exports = module.exports = {}; |
2) Assign any expression in
greetings.js
that we want to become available in other files to the exports
object:
1
2
3
4
5
6
7
8
9
10
| // greetings.js // var exports = module.exports = {}; exports.sayHelloInEnglish = function () { return "HELLO" ; }; exports.sayHelloInSpanish = function () { return "Hola" ; }; |
In the code above, we could have replaced
exports
with module.exports
and achieved the same result. If this seems confusing, remember that exports
and module.exports
reference the same object.
3) This is the current value of module.exports:
1
2
3
4
5
6
7
8
9
| module.exports = { sayHelloInEnglish: function () { return "HELLO" ; }, sayHelloInSpanish: function () { return "Hola" ; } }; |
Importing a Module
Let’s import the publicly available methods of
greetings.js
to a new file called main.js
. This process can be described in three steps:
1) The keyword
require
is used in Node.js to import modules. Imagine that this is how require
is defined:
1
2
3
4
5
6
| var require = function (path) { // ... return module.exports; }; |
2) Let’s require
greetings.js
in main.js
:
1
2
| // main.js var greetings = require( "./greetings.js" ); |
The above code is equivalent to this:
1
2
3
4
5
6
7
8
9
10
| // main.js var greetings = { sayHelloInEnglish: function () { return "HELLO" ; }, sayHelloInSpanish: function () { return "Hola" ; } }; |
3) We can now access the publicly available methods of
greetings.js
as a property of our greetings
variable in main.js
.
1
2
3
4
5
6
7
8
| // main.js var greetings = require( "./greetings.js" ); // "Hello" greetings.sayHelloInEnglish(); // "Hola" greetings.sayHelloInSpanish(); |
Salient Points
The keyword
require
returns an object, which references the value of module.exports
for a given file. If a developer unintentionally or intentionally re-assigns module.exports
to a different object or different data structure, then any properties added to the original module.exports
object will be unaccessible.
An example will help elaborate this point:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // greetings.js // var exports = module.exports = {}; exports.sayHelloInEnglish = function () { return "HELLO" ; }; exports.sayHelloInSpanish = function () { return "Hola" ; }; /* * this line of code re-assigns * module.exports */ module.exports = "Bonjour" ; |
Now let’s require
greetings.js
in main.js
:
1
2
| // main.js var greetings = require( "./greetings.js" ); |
At this moment, nothing is different than before. We assign the variable
greetings
to any code that is publicly available in greetings.js
.
The consequence of re-assigning
module.exports
to a data structure other than its default value is revealed when we attempt to invoke sayHelloInEnglish
and sayHelloInSpanish
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // main.js // var greetings = require("./greetings.js"); /* * TypeError: object Bonjour has no * method 'sayHelloInEnglish' */ greetings.sayHelloInEnglish(); /* * TypeError: object Bonjour has no * method 'sayHelloInSpanish' */ greetings.sayHelloInSpanish(); |
To understand why these errors are occuring, let’s log the value of
greetings
to a console:
1
2
| // "Bonjour" console.log(greetings); |
At this point, we are trying to access the methods
sayHelloInEnglish
and sayHelloInSpanish
on the string “Bonjour.” module.exports
, in other words, is no longer referencing the default object that contain those methods.Conclusion
Importing and exporting modules is a ubiqutous task in Node.js. I hope that the difference between
exports
and module.exports
is clearer. Moreover, if you ever encounter an error in accessing publicly available methods in the future, then I hope that you have a better understanding of why those errors may occur.
No comments:
Post a Comment