https://www.sitepoint.com/understanding-module-exports-exports-node-js/
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:
模块是把一些代码封装在一起的玩意儿。当创建一个模块的时候,这个可以被理解为把很多相关的函数放到一个文件里面。我们来看一个例子,假设我们创建了一个文件叫做greetings.js 包含如下两个函数
// 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:
使用 greetings.js 提高党这个封装的代码能够被文件调用。我们用下面三个方式
1) Imagine that this line of code exists as the first line of code in greetings.js:
// 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:
在greetings.js 中我们希望能够在别的文件中使用,导出对象
// 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.
在这个代码中,我们用exports替换了module.exports。
3) This is the current value of module.exports:
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:
这个是重要的导入一个greetings.js 叫做main.js. 分三步来做
1) The keyword require is used in Node.js to import modules. Imagine that this is how require is defined:
var require = function(path) {
// ...
return module.exports;
};
看到没,虽然用require 但是指上是module.exports
2) Let’s require greetings.js in main.js:
我们require一下greeting.js
// main.js
var greetings = require("./greetings.js");
The above code is equivalent to this:
和下面等价
// 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.
我们可以访问greetings.js
// main.js
var greetings = require("./greetings.js");
// "Hello"
greetings.sayHelloInEnglish();
// "Hola"
greetings.sayHelloInSpanish();
Important 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.
关键字require返回一个对象,这个指向module.exports对一个指定的文件,如果开发者再次指向module.export 到一个不同的对象或者数据结构,那么任何添加到module.exports 的对象就不能被访问到
An example will help elaborate this point:
// 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:
然后我们require一下
// 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:
我们重新绑定了module.exports到一个变量
// 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();
Now let’s require greetings.js in main.js:
// 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:
// 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:
// "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.