原文
Node.js 通过实现 CommonJS 的 Modules/1.0 标准引入了模块(Module)概念,一个模块可以通过 module.exports
或 exports
将函数、变量等导出,以使其它 JavaScript
脚本通过 require()
函数引入并使用。
现在有一个问题:到底应该用 module.exports
还是用 exports
呢?
最好的方法就是查看 Node.js 的 官方文档中关于 module 的介绍:
In particular module.exports is the same as the exports object.
可以看出 module.exports
和 exports
其实是一样的。在代码里比较:
1 | console.log(module.exports === exports); |
然而参照 “module.exports vs exports in nodeJS” 中的例子,考虑下面的代码:
1 | // a1.js |
执行 node b
,输出结果如下:
1 | {} |
可见 a1.js 的 function
导出失败了,而 a2 却成功了。原因是什么呢?搜索无果后我直接查看了 Node.js 的源代码:
1 | // file path: node/lib/module.js |
这段代码的作用是为 global
赋属性并调用 runInThisContext()
函数运行模块(其内容已经事先读入到 content
变量)。模块中使用的 exports
(即 global.exports
)其实是对 self.exports
的引用,对 exports
进行修改会影响到 self.exports
,但如果对其赋值,exports
则不再是 self.exports
的引用了。而对 module.exports 赋值自然就没有问题。
了解这个,有些 Node.js 模块的源代码中的 exports = module.exports = someObject
也可以理解了:只使用 module.exports = someObject
的话 module.exports
引用的地址变了,而 exports
引用的还是之前的地址,所以下面的代码中再修改 exports
就不会再改变 module.exports
的值了。
总结
exports
是module.exports
的一个引用require
引用模块后,返回给调用者的是module.exports
而不是exports
exports.xxx
,相当于在导出对象上挂属性,该属性对调用模块直接可见exports =
相当于给exports
对象重新赋值,调用模块不能访问exports
对象及其属性- 如果此模块是一个类,就应该直接赋值
module.exports
,这样调用者就是一个类构造器,可以直接new实例