文本参考了这篇原创文章:
http://qifuguang.me/2015/11/11/揭秘Node-js中exports和module-exports/
Nodejs使用模块化工具管理的原理,每个独立的js文件都可以看做是一个模块,每个模块中都隐含着exports和和module.exports两个对象。
系统自动给nodejs 文件增加2个变量 exports 和 module, module 又有一个属性 exports, 这个exports 属性指向一个空对象 {}; 同时 exports这个变量也指向了这个空对象{};
首先我们得先摆出两条不变的真理:
- exports一开始是指向module.exports的;
- 通过require得到的是module.exports中的内容,而不是exports的内容;
exports和module这两个对象是所有Node.js类型的文件中都默认隐式存在的,比如我们新建一个test.js文件:
console.log(exports);console.log(module); 终端显示结果: {} Module { id: '.', exports: {}, parent: null, filename: 'C:\\nodejs\\workspace\\exports_module.exports.js', loaded: false, children: [], paths: [ 'C:\\nodejs\\workspace\\node_modules', 'C:\\nodejs\\node_modules', 'C:\\node_modules' ] }
可以看到,test.js文件中并未声明exports和module对象,但是它们确实存在。并且可以看到,exports的初始值是{},而module的初始值有一大串属性,其中还包含一个exports属性,它的初始值也是{}。
实际上,一开始exports就是指向module.exports的,引用关系如下图:
然后,我们来创建一个my_module.js文件:
再在同一个目录下创建app.js文件:// 为exports增加一个属性sayHello(属性值为函数),指向未变(还是指向module.exports)exports.sayHello = function() { console.log('Hello world!'); // 查看exports和module.exports console.log(exports); console.log(module.exports); }
myModule = require('./my_module');myModule.sayHello(); 终端显示结果: Hello world! { sayHello: [Function] } { sayHello: [Function] }
所以现在exports和module.exports是这样的:
接着,我们再来创建一个my_module2.js文件:
// exports被重新分配了一块新的内存,而不再指向module.exports了。 exports = {sayHello: function() {console.log('Hello world!');}} console.log(exports);
然后将app.js文件修改为以下内容:
myModule = require('./my_module2');console.log('module.exports:');console.log(module.exports);myModule.sayHello(); 终端运行出错了!!! C:\nodejs\workspace\app.js:4 myModule.sayHello(); ^ TypeError: myModule.sayHello is not a function at Object.<anonymous> (C:\nodejs\workspace\app.js:4:10) at Module._compile (module.js:409:26) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Function.Module.runMain (module.js:441:10) at startup (node.js:139:18) at node.js:974:3
这个时候,exports和module.exports的状态是这样的:
将app.js中的myModule.sayHello();注释掉,然后重新运行app.js,输出结果如下:
{ sayHello: [Function] }
module.exports:
{}
从输出中也可以看到,此时的module.exports={},所以肯定找不到sayHello函数,那必然报错!
而exports的输出为:{ sayHello: [Function] }
结论:
1.最好别分别定义module.exports和exports
2.NodeJs开发者建议导出对象用module.exports,导出多个方法和变量用exports
3.require返回的是module.exports,在module.exports上可以设置函数、对象实例、基本类型的变量等,因此,一般就是module.exports作为模块的导出就行了。
如果想用exports作为模块的返回,那么就为它设置一个属性,并且不要在module.exports上设置同名的属性。