// logger.js
module.exports = function(message) {
// ...
}该模式的的一个扩展就是将上面提到的命名导出组合起来,虽然它仍然只是提供了一个入口点,但是可以使用次要的功能
module.exports.verbose = function(message) {
// ...
}虽然看起来暴露一个函数是一个限制,但是它是一个很完美的方式,把重点放在一个函数中,代表该函数是这个模块最重要的功能,而且使得内部私有变量属性变的更透明
Node的模块化也鼓励我们使用单一职责原则,每个模块应该对单个功能负责,从而保证模块的复用性
构造函数导出
将构造函数导出,是一个函数导出的特例,但是区别在于它可以使得用户通过它区创建一个实例,但是我们仍然继承了它的prototype属性,类似于类的概念
class Logger {
constructor(name) {
this.name = name;
} log(message) {
// ...
}
info(message) {
// ...
}
verbose(message) {
// ...
}
}
const Logger = require('./logger');
const dbLogger = new Logger('DB');
// ...实例导出
我们可以利用require的缓存机制轻松的定义从构造函数或者是工厂实例化的实例,可以在不同的模块中共享
// count.js
function Count() {
this.count = 0;
}Count.prototype.add = function() {
this.count++;
}
module.exports = new Count();
// a.js
const count = require('./count');
count.add();
console.log(count.count)
// b.js
const count = require('./count');
count.add();
console.log(count.count)
// main.js
const a = require('./a');
const b = require('./b');
输出的结果是
1
2
该模式很像单例模式,它并不保证整个应用程序的实例的唯一性,因为一个模块很可能存在一个依赖树,所以可能会有多个依赖,但是不是在同一个package中
修改其他的模块或者全局作用域
一个模块甚至可以导出任何东西这可以看起来有点不合适;但是,我们不应该忘记一个模块可以修改全局范围和其中的任何对象,包括缓存中的其他模块。请注意,这些通常被认为是不好的做法,但是由于这种模式在某些情况下(例如测试)可能是有用和安全的,有时确实可以利用这一特性,这是值得了解和理解的。我们说一个模块可以修改全局范围内的其他模块或对象。它通常是指在运行时修改现有对象以更改或扩展其行为或应用的临时更改。









