module.exports与exports的联系与区别
首先说明他们是啥?
在CommonJS规范中,exports和module.exports这两个对象是把某一模块化文件中的属性和方法暴露给外部模块的接口(说法可能不准确),外部模块通过require引用返回的对象可调用module.exports中的属性和方法。
module.exports与exports的联系
1. 每一个node.js执行的模块化文件,都会自动创建一个module对象,module对象有一个叫exports的属性,module.exports 初始值为一个空对象 {} ,同时自动创建了一个exports对象,该对象也是一个空对象{},通过VSCode运行调试一段模块化文件代码,在Local变量中我们可以看到这个特点:
2. exports对象是指向的 module.exports 的引用,相当于 :exports = module.exports;
要导出该模块的属性或方法时,我们可以用点操作符给module.exports对象添加一对属性及属性值:
module.exports.test = test;
当然,我们也可以给exports添加,由于exports和module.exports指向同一块内存,就相当于该属性添加到module.exports上:
exports.test = test;
所以执行如下两句代码后,exports对象和module.exports对象会同步由一开始的空对象更新为 {a: 1, b: 2}
module.exports.a = 1;
exports.b = 2;
module.exports与exports的区别
在另一个模块引入该模块时,require() 返回的是 module.exports 而不是 exports。
所以我们不能直接用对象字面量给exports赋值,这样exports就指向了新的内存,切断了exports与module.exports之间的联系,这时exports和普通的对象就没有区别了,无法被导出:
exports = { test: 1 }
如果要直接使用对象字面量,我们可以直接把它赋值给module.exports:
module.exports = { test: 1 }
要注意,如果我们使用这种方式给module.exports赋值了,那再用点操作符给exports赋属性和属性值的方式就失效了,因为module.exports指向了新的内存区域,同样切断了和exports对象的联系。同样的,在此之前用点操作符给module.exports赋值的 语句也失效了,因为module.exports对象被新的对象字面量覆盖了。