commonJS specification
commonJS规范
导入导出模块的方式
导出方式
- 使用
exports
对象导出模块
exports实质上是node全局的module上的一个属性,它是一个对象。既然是一个js对象,我们就可以在它身上挂载属性和方法。
可以这样去挂载
1 | exports.name = '张三' |
- 使用
module.exports
导出模块
这种方式导出模块其实本质上是和上面的方式一样的,只不过是一个写法的不同而已。
1 | module.exports = { |
一般我们现在一个文件里面编写好了各种函数、代码、对象等等,最后使用module.exports
导出模块。
1 | function add(a, b) { |
导入方式
通过require
函数导入模块
1 | const module = require('/filepath/.../filename.js') |
当一个模块,比如写了一个工具函数模块,这个工具函数模块里面有非常的多的函数,我们只需要其中的一个函数,那么我们可以这样导入
1 | const {add} = require('/filepath/.../utils.js') |
变量哪里来?
在node环境下,每一个文件会被视作一个独立的模块,每个模块都会有自己的作用域。
node.js会这个模块进行一个封装,把它封装到一个函数里面,也就是把我们每个模块里面的代码全都放到了一个函数里面,
这个函数带有5个参数,分别是exports
、require
、module
、__filename
、__dirname
。
所以我们能在文件里面使用这些变量,是因为node.js帮我们传递了这些参数。
- 一个示例js文件
1 | console.log("hello") |
- 它会被node.js封装成这样
1 | (function (exports, require, module, __filename, __dirname) { |
require循环引用,执行机制
在node.js中,require是同步加载的,当一个模块被引入的时候,会先执行这个模块的代码,然后再引入其他模块。
node.js模块加载缓存机制
- 首次加载:当一个模块第一次被
require
时,Node.js 会执行该模块的代码,并将其导出的内容缓存起来。 - 缓存存储:缓存存储在require.cache对象中,该对象的键是模块的绝对路径,值是模块的导出对象。
- 再次加载:当再次
require
一个模块时,Node.js 会首先检查该模块是否已经被加载过,如果是,则直接从缓存中取出该模块的导出对象,否则,Node.js
会再次执行该模块的代码,并将其导出的内容缓存起来。
简单分析一下循环引用的过程。
1 | node main.js |
循环引用代码:
1 | // main.js |
- 入口文件main.js中导入了模块
a
,这个时候会执行a.js文件,a1的值被设置为true了,然后又导入了模块b
。 - 开始执行b.js文件,导入了模块
a
,这个时候a.js文件已经被执行过了(node会到缓存里面去找)
,所以不会再次执行,直接从缓存中取出a.js文件的导出对象,这个时候a1的值是true,a2的值还没有被设置,所以a2的值是undefined。 - b文件打印出
in b, a.a1 = true, a.a2 = undefined
。 - 回去继续执行a.js文件,由于b.done没有这个值,所以a文件的第三行的输出会是
in a, b.done = undefined
。 - a文件的最后一行设置了a2的值为true。
- 回到main.js文件,打印出
in main, a.a1 = true, a.a2 = true
。
拓展阅读
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 cles's blog!
评论