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.jssayHelloInEnglish = 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.jsvar exports = module.exports = {}; |
2) Assign any expression in
greetings.js that we want to become available in other files to the exportsobject:
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.jsvar greetings = require("./greetings.js"); |
The above code is equivalent to this:
1
2
3
4
5
6
7
8
9
10
| // main.jsvar 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 greetingsvariable in main.js.
1
2
3
4
5
6
7
8
| // main.jsvar 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.jsvar 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
exportsand 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