commonJS
一、使用
-
导入:require
-
导出:exports 、module.exports
二、深入解析
1.require 导入的是谁?
由图可知 exports 实际上是将你想要暴露的所有变量、对象都作为属性挂载在exports 对象中
require函数 实际上做的事是返回指定模块的 module.exports 对象的地址指针(后面我们讲为什么导出的是module.exports)
2.exports 和 module.exports 的关系
exports === module.exports >>> true
通过上面的代码我们可以发现,exports 和 module.exports 是指向的是同一个对象
3.node 是如何实现 exports === module.exports
我们要清楚一点 Module 是一个模块类,它用来描述一个模块文件
在 new Module() 这个类之后
const module = new Module()
const exports = {}
mudule.exports = exports
Node 将 exports 变量 赋值给了module.exports,这导致他们产生了关联
而我们最重要需要知道的一点是:require 导入的是module.exports,而不是 exports
很残酷的是,当 module.exports 指向 exports 的时候,exports 非常有用。
当我们覆盖 module.exports 的时候,exports 就像一个小丑,不伦不类。
陷阱
如果你只打算使用 exports,那么你绝对不要直接让它指向令一个对象。
因为你覆盖了 exports 它原来和 module.exports 的联系就彻底断开,你必须通过 exports 原本的引用来修改 module.exports。如果你覆盖了原本的引用,你的 module.exports 将永远指向一个空对象,除非你去修改 module.exports
bar.js
// node 初始化...
内存地址: 0x100000 -> {空}
exports -> 0x100000 {空}
module.exports -> 0x100000 {空}
新建对象:0xb11111 -> {name:'zlx'}
// 覆盖exports
exports -> 0xb11111 {name:'zlx'}
module.exports -> 0x100000 {空}
main.js
// 导入 module.exports
const bar = require(bar.js) >>> 0x100000 {空}
//看吧,别覆盖 exports
4.为什么要存在 exports 这样一个鸡肋的变量?
因为 commonJS 规范上只提到 exports ,module.exports 是 node 在实现的时候的一个封装类。node 为了符合 commonJS 规范不得不做出让步,因此搞了个不伦不类的 exports。
5.总结
- require 的返回值是 module.exports
- module.exports 和 exports 初始化时指向同一个指针引用
- 在只打算使用 exports 时,请不要覆盖 exports 的引用
- exports 的存在是为了满足 commonJS 规范
- 实战中个人觉得module.exports更加好用