两者的关系
exports = module.exports = {}
nodejs如何导出模块
当不改变module.exports和exports的指向,module.exports和exports均可导出,因为上面也说过这两个对象实际上指向的都是同一个堆地址
不改变指向
//a.js
exports.a = 1;
module.exports.b = 2;
//b.js
const test = require('./a');
console.log(test);
//output: { a: 1, b: 2 }
改变指向:仅module.exports可导出
//a.js
exports.a = 1; // exports = { a: 1 };
module.exports = { b: 2 };
//b.js
const test = require('./a');
console.log(test);
//output: { b: 2 }
刨根问底
为什么指向一旦被改变exports就不能导出对象了呢?
首先node加载模块的时候会用一个函数将代码包裹
(function (exports, require, module, __filename, __dirname) {
});
当加载模块的时候,module已经被当作参数传入,所以即使module.exports的值改变也能够在其他文件中进行调用,也就是为什么指向一旦被改变,只有module.exports可导出。
那么有同学问了exports也被当作参数传入啦~~~
另外node(commonjs)加载模块时,其实是进行的一个浅拷贝(基本类型一样,引用类型拷贝地址),所以单独改变模块里面的变量值(非引用类型),并不会影响导入的值,而es6的import则是创建一个动态的只读引用,等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
利用node-inspector调试我们可以找到答案
Module.prototype._compile = function(content, filename) {
......
let result;
//这里传入的exports其实是this.exports,而当前this是指向module的,所以加载模块传入的exports其实是module.exports,所以一旦改变了exports指向,就不能通过exports导出了
const exports = this.exports;
const thisValue = exports;
const module = this;
if (requireDepth === 0) statCache = new SafeMap();
if (inspectorWrapper) {
result = inspectorWrapper(compiledWrapper, thisValue, exports,
require, module, filename, dirname);
} else {
result = ReflectApply(compiledWrapper, thisValue,
[exports, require, module, filename, dirname]);
}
hasLoadedAnyUserCJSModule = true;
if (requireDepth === 0) statCache = null;
return result;
};
网友评论