我们在阅读它人或开源的node.js代码时,会发现在对模块导出的写法上会出现下面几种情况,而关于导出的方法整理,可以参见我这篇文章node.js中exports的用法整理。现在,我们以导出字符串对象为例:
在module.js文件中,有如下写法:
- 1.exports.get_name = ‘fungwan by exports ‘;
- 2.module.exports.get_name = ‘fungwan by modules’;
- 3.module.exports = ‘fungwan by modules’;
通过对比发现,这里较之前多了module.exports,那么它跟exports的导出有什么关系呢?查阅资料即可知晓,其实exports就是module.exports对象的引用,本质上是相等的。我们可以通过这句代码证实:
1 | console.log(module.exports === exports); |
它打印出来是true。不过我们真正要require出来的是只是module.exports这个对象!
等等,这里又提到了引用,相信熟悉C++或Java的人应该都对引用或有深刻的认识,即我们对引用的对象进行了属性的修改,那么被引用的对象的属性也会被修改。这就是为什么我们在module.js仅对exports.some_words属性进行修改,而在真正导出的module.exports的对象中,我们在外面(另一个需要require的文件)也可拿到some_words这个字符串对象值。
这里我们新建一个main.cpp文件,用C++代码来说明一下上述观点:
1 |
|
接着我们在入口函数里面,去实例化一个名为module_exports的对象,就类似于我们真正require的是module_exports。
1 |
|
但是,当我们在一个类似于module.js的模块文件中,同时有exports和module.exports的导出时,后者是会覆盖前者的导出,所以一般在模块文件中只用其中一种方式导出。
##需要注意的一点
我们在导出的写法上有一点是要避免,因为它是错误的,比如在对字符串对象的导入:
1 | exports = 'fungwan by exports ';//error |
这种导出的方式其实是给exports重新赋值了(内存的指向位置发生了变化),即已不是module.exports的引用,exports的修改影响不到module.exports。所以当我们在外部用require时会发现导出的是一个空{}。还是拿上面C++的例子说明一下,我们继续在main函数里面,重新实例化一个C_require对象,然后用exports指向新的这个对象:
1 |
|
针对上面的错误的导出方式有一个解决办法:1
exports = module.exports = 'fungwan by exports ';
但是如果像这样,还不如直接就只写成module.exports = 'fungwan by exports'
;
最后,再来说说根据不同的导出方式,我们在require的时候需要注意些什么?关键还是要理解属性跟对象的关系。还是以代码的方式,下面我都以module.exports导出,可以跟之前的这篇node.js中exports的用法整理的代码进行对比:
导出一个字符串1
module.exports = 'string by modules';
导出一个类1
2
3
4
5
6
7
8
9
10
11
12function helper() {
var number = '';
this.do = function () {
console.log('I can help you!');
}
};
helper.prototype.giveMoney = function(){
console.log('I have lots of cash!');
}
module.exports = helper;
那么在require的时候,我们的方式是:
require一个字符串1
2var lib = require('./module.js');
console.log(lib);
require一个类对象1
2
3var lib = require('./module.js');
var c_help = new lib();
c_help.giveMoney();