node.js中的模块化

Node.js 中的模块化

Node 使用了 CommonJS 模块化标准。通过 exports 暴露 ,require 导入。

CommonJS 是同步的 ,会等待模块加载完后再继续执行。而 ES module 默认是异步加载的。

Node 一开始并不支持 ES module 。 现在能使用 ,不过可能需要相关配置。

需要了解可以戳这 Node.js 如何处理 ES6 模块-阮一峰

导入与导出

require

requrie是 node 的全局方法 。在任何 js 文件里都可以使用。

它的作用有两点:

  • 执行模块里的代码

  • 返回模块暴露的数据

require 是同步方法 ,并且在第一次加载模块时会将结果缓存 ,第二此以后的导入时不会重新加载而是直接从缓存里拿结果。

image-20211016171214890

node a.js 输出的结果是 c c3 b a c3 c2

因此我们可以看出 require 方法是同步的 。

并且 c 模块被导入了两次, c3 被输出了两次 ,但 cc2 只输出一次 。因此第二次导入 c 模块时并没有去加载 c 模块而是直接从缓存里拿到结果 c3

require 的参数

require 方法接收一个参数。叫模块标识符

参数不一定是路径 , 如我们导入 http ,fs 等核心模块或者是第三方库 art-template ( 模板引擎 )

模块标识符有以下 3 种情况

  • 路径

路径开头是一定带有 ./ 或者 ../ 的 ,这一般用来加载我们自己写的模块 (自定义模块)。

它加载时会顺着路径找到模块 ,然后执行,返回暴露的数据(没有默认就是空对象)

可以省略 .js 后缀 。

  • Node 提供的核心模块(http ,fs …)

Node 的核心模块我们在下载 Node 时就下载了,它已经被放在 Node 程序里了。因此我们导入 Node 模块时 ,Node 识别后会直接加载。

  • 第三方模块

第三方模块(库)需要我们提前下载好 ,下载好的第三方模块会被放到 node_module 文件夹内 。

第三方模块于 Node 的核心模块写法一样,就是它的名称。但任何第三方模块于 Node 核心模块的名称都不一样。因此如果不是核心模块和自定义模块 ,便会去 node_module 里找。

在node_module 里查找模块有点类似原型链。

也就是如果当前目录下没有 node_module . 就会去上级目录找 。一直到磁盘根目录都没有,没有就报错。

当然如果我们全局安装了。那么即使此项目里没有安装,也可以使用。

但一个项目都是有且仅有一个 node_module 文件夹。容易管理且统一存放。放在项目根目录下。项目的所有文件都可以访问。

exports

模块于模块之间的作用域是不同的 。这些模块作用域不能相互包含

因此即使 B 模块在 A 模块里导入 ,A模块也不能直接使用 B 模块里的变量。

如果需要把模块上的数据方法提供给其他模块使用。需要使用 exports 。其他模块可通过 require 的返回值得到

单数据导出

module.exports=yyy

如导出一个对象 ,导出一个字符串,数组,数字。

// 对象
module.exports = {...}
// 数组
module.exports = [...]
// 字符串
module.exports = '...'
// 数值
module.exports = 123
多数据导出
  • module.exports.xxx=yyy

  • exports.xxx = yyy

// 通过 module.exports
module.exprots.num = 111
module.exports.obj = {...}
                      
// 通过 exports
exports.num = 111
exports.obj = {...}

注意

  • module.exports.xxx= yyyexports.xxx=yyy 是一样的

  • 单数据导出不能使用 exports = xxx 。原因我们得从它的导出原理来得出。

原理

Node 中 ,每一个 js 文件就是一个模块 。每一个模块就是一个函数 。

也就是 Node 会给文件里的代码外包一个函数 。同时添加一些必要的代码 。然后再加载时执行这个函数。

而这些函数之间没有作用域的包含。因此变量之间并没有联系。

每个模块都能访问到 Node 提供的 module 对象。就好比 在游览器里能访问 window 一样。

module 对象里有一个成员 exports ,它的值默认是一个空对象

当模块第一次被加载时,相当于执行了存放模块的函数。在全部代码执行完毕后,在最后会把 module.exports 返回 , 返回的数据作为 require方法的返回值。

因此我们可以把需要暴露的数据放在 moduel.exports 对象里,也可以直接给它赋值。也就是单数据导出。

但如果我们暴露多条数据 ,每次都 module.exports.xxx = yyy 可得烦死。

因此在每个模块开头,又执行了一行代码(不可见)。

var exprots = module.exports

那么 exports 的地址是与 module.exports 同地址 。因此给 exports 添加成员相当于给 module.exprots 添加成员。那么多数据导出时,就不必加上 module 了。

但最后返回出去的是 module.exprots 。 这也就是说 ,如果我们直接给 exports 赋值。如 exports = '单数据'

那么就会断开 exports 于 module.exprots 的关联(同地址) 。那么最后的数据 (添加的 ‘单数据’) 这不会被导出。

模拟模块处理
function Mymodule(){
    var exports = module.exports
    // ..... JS 文件内的可见代码
    return module.exports
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无糖的酸奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值