之前有了解Node.js的相关内容,也有用node.js和express框架写过一个个人博客,然而对于一些原理性的知识还是知之甚少,今天看到自己写的博客项目上面有用到exports和module.exports两种方法来导出一些模块,方便之后的模块去引用,就看了下两者的区别。下面是我的总结:
一. 两者的常见用法:
1 . exports的常见用法:
exports.name = 'XXX';
exports.something = function (){
//...
};
2 . module.exports的常见用法:
function Func(x, y){
this.x = x;
this.y = y;
}
Func.prototype.something = function (){
//...
}
module.exports = Func;
我们可以看出,一般一个js文件中会出现不止一个exports,而且是以添加属性的形式赋值;然而module.exports在一个文件中只出现一次,为什么会有这样的用法呢?我们继续往下看就会真相大白了!
二. module.exports和exports的原理
exports和module都是系统创建的两个对象,在module.exports中的exports只是module的一个属性,在初始化时:exports = module.exports = {};
可以看出exports只是module.exports的一个引用。下面来看个js的小例子,就会明白两者的区别了。
var module = {};
module.exports = {};
var exports = module.exports; //exports和module.exports指向同一块内存
exports.name = 'luwenjing';
console.log(module.exports.name); //luwenjing
从上面的例子可以看出,如果给exports添加一个属性,就相当于给module.exports添加了一个属性。那如果改一下module.exports的内存指向呢?
var module = {};
module.exports = {};
var exports = module.exports;
exports.name = 'luwenjing';
module.exports = {};
console.log(module.exports.name); //undefined
可以看到,如果改了内存指向,module.exports就会指向新的内存,name属性就自然不存在了。
看到这里应该有人会说,这不就是引用类型本身的特性吗,用得着你在这再重复一遍。不急,不急,如果你看到这里已经知道exports和module.exports在用法上的区别的原理时,那你就不用再往下看了,潇洒的离开便好,如果你还有疑问就继续吧!
三. 加深理解
1 . 实际我们在使用require导入模块时,导入的是module.exports的值:
exports.name = 'XXX';
exports.something = function (){
//...
};
如上面的代码块,以为exports和module.exports指向同一块内存,所以此时的
exports = module.exports = {
name: 'XXX',
something: function (){
//...
}
}
所以require时也就自然得到了name和something的值。
2 . 那如果在一个js文件中同时存在exports和module.exports会怎样呢?
exports.name = 'XXX';
exports.something = function (){
//...
};
module.exports = {};
还记得上面的代码的同学就会知道,此时module.exports指向了新的内存,如果我们再用require导入后获得name属性就会输出undefined。
总结:exports是module.exports的引用,所以在使用exports导出时,相当于全部赋给了module.exports,前提是module.exports不具有任何属性和方法,如果module.export已经具备一些属性和方法,那么exports添加的信息将被忽略。因为require始终引入的都是module.exports的值。
所以如果要导出的是一个个单独的属性或方法时用exports;
如果要导出的是一个构造函数或一个对象,其中的属性和方法相互关联就使用module.exports。