咱们知道NodeJS遵循
CommonJS
的规范,使用require
关键字来加载模块,使用exports
和module.exports
来导出模块,那么这两个导出又有什么关系或者区别呢?html
其实,在node执行一个文件时,会给这个文件内生成一个 exports
对象和一个 module
对象,而这个module
对象又有一个属性叫作 exports
node
新建一个index.js文件 执行 node index.js
命令api
console.log(exports)
console.log(module)
复制代码
能够看出控制台的输出结果以下: bash
exports
和
module.exports
有什么关系呢? 咱们在index.js 文件中添加一句代码
console.log(exports === module.exports)
复制代码
会发现结果是 true
这说明,文件开始执行的时候,它们是指向同一块内存区域的app
graph LR;
A[exports] ; B[内存:xxx]; C[module.exports]
A-->B
C-->B
复制代码
当文件执行完毕的时候,只有module.exports
变量被返回了,以便后续被其余模块 require
引用,为了证实这个观点,咱们能够新建一个文件 index2.js 进行测试 index2.js测试
exports.a = 1
复制代码
而后在 index3.js 中引用ui
const module2 = require('./index2')
console.log(module2)
复制代码
控制台输出: { a: 1 }
而后咱们在 index2.js 中添加代码:spa
exports.a = 1
module.exports = {
b:2
}
复制代码
在这里同时使用两个导出方法,查看控制台输出结果为 { b: 2 }
此时,咱们继续在 index2.js 文件中添加code
console.log(exports === module.exports)
复制代码
结果为false
,此时的 exports
和 module.exports
已经不是指向同一块内存地址了,由于前面的代码里面,咱们使用了cdn
module.exports = {
b:2
}
复制代码
这致使了 module.exports
从新指向了新的内存地址, 可是当咱们执行 node index3.js
查看index3.js 的运行结果时,看到的是 {b:2}
而不是 {a:1}
证实了咱们上面的观点: 只有module.exports
变量被返回了 所以,初始化的状态,咱们能够用以下代码来帮助理解:
var module = {
exports:{}
}
var exports = module.exports
复制代码
而最终的导出结果是 module.exports
这个对象. 到了这里,可能有人又会有疑问,为啥以前不少的模块都是须要引入才能使用,可是exports
和module.exports
咱们没有引用却能直接使用? 这个问题的答案咱们能够从Node的官方文档中找到答案,
(function(exports,require,module,__filename,__dirname){
...
})
复制代码
在进行了头尾封装后,各模块之间进行了做用域的隔离,避免了污染全局变量,经过头尾封装,实现了
总结:
exports
对象是 module
对象的一个属性,在初始时 module.exports
和 exports
指向同一块内存区域module.exports
, exports
只是对它的引用,在不改变exports
内存的状况下,修改exports
的值能够改变 module.exports
的值module.exports
,以避免由于各类赋值致使的混乱