在说exports和module.exports之前,先来说一说创建模块
模块
模块可能是一个文件,也可能是包含一个或者多个文件的目录,如果模块是个目录,Node通常会在这个目录下寻找一个交index.js的文件作为入口。
典型的模块是一个包含exports对象属性定义的文件,这些属性可以是任意类型的数据,比如字符串,对象和函数。
例如,我们可以定义如下模块:
var name = 'xiaoming';
exports.sayHello = function(message){
console.log(name + 'say:' + message);
}
exports.learn = function(){
console.log(name + 'wants to learn nodejs well');
}
exports对象上只设定了两个属性。也就是说引用代码只能访问到sayHello和learn两个函数。而变量name作为私有变量仅作用在sayHello和learn两个函数的逻辑内部,程序不能直接访问它
使用新的模块,需要require函数,node以同步的方式寻找它,定位到这个模块并加载文件中的内容。require是Node中少有的几个同步I/O操作之一。
Node定位到并计算好你的模块之后,require函数会返回这个模块中定义的exports对象中的内容。
用exports对象能满足大多数的模块查创建需要,但是你有可能需要用不同的模型创建该模块。比如我们想让之前的模块只返回一个构造函数,而不是包含两个函数的对象。
如果只需要从模块中得到一个函数,那么从require中返回一个函数的代码要比返回一个对象的代码更优雅。
但是直接把exports设定成你想返回的东西是不可以的。因为Node认为不能用任何其他对象,函数或变量给exports赋值。
var Currency = function(canadianDollar){
this.canadianDollar = canadianDollar;
}
Currency.prototype.roundTwoDecimals = function(amount){
return Math.round(amount*100)/100;
}
exports = Currency;
这样会导致这个模块不可用,为了让上面的模块可用,需要将exports替换成module.exports。用module.exports可以对外提供单个变量,函数或者对象。如果你创建了一个既有exports又有module.exports的模块,它会返回module.exports,而exports会被忽略
在最终程序中导出的是module.exports.exports只是对module.exports的一个全局引用,最初被定义为一个可以添加属性的空对象。所以exports.myFunc只是module.exports.myFunc的简写。
将exports设定为别的,就打破了module.exports和exports之间的引用关系,因为真正导出的是module.exports,那样exports就不能用了,因为它不再指向module.exports。如果想维持那个链接,需要像下面这样:
module.exports = exports = Currency;