Defining and using modules
JavaScript as a language does not have mechanisms to define real classes. In fact, everything in JavaScript is an object. We normally inherit properties and functions from one object to another. Thankfully, Node.js adopts the concepts defined by CommonJS—a project that specifies an ecosystem for JavaScript.
We encapsulate logic in modules. Every module is defined in its own file. Let's illustrate how everything works with a simple example. Let's say that we have a module that represents this book and we save it in a file called book.js
:
We defined a public property and a public function. Now, we will use require
to access them:
We will now create another file named script.js
. To test our code, we will run node ./script.js
. The result in the terminal looks like this:
Along with exports
, we also have module.exports
available. There is a difference between the two. Look at the following pseudocode. It illustrates how Node.js constructs our modules:
So, in the end, module.exports
is returned and this is what require
produces. We should be careful because if at some point we apply a value directly to exports
or module.exports
, we may not receive what we need. Like at the end of the following snippet, we set a function as a value and that function is exposed to the outside world:
In this case, we do not have an access to .name
and .read
. If we try to execute node ./script.js
again, we will get the following output:
To avoid such issues, we should stick to one of the two options—exports
or module.exports
—but make sure that we do not have both.
We should also keep in mind that by default, require
caches the object that is returned. So, if we need two different instances, we should export a function. Here is a version of the book
class that provides API methods to rate the books and that do not work properly:
Let's create two instances and rate the books with different points
value:
The logical response should be 10 20
, but we got 20 20
. This is why it is a common practice to export a function that produces a different object every time:
Now, we should also have require('./book.js')()
because require
returns a function and not an object anymore.