目录
1什么是模块化
编程领域的模块化就是遵守固定的规则,把一个大文件拆分成独立相互依赖的多个小模块。
拆分后提高了代码的复用性,可维护性和按需加载。
因此我们提出模块化规范:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大的方便了各个模块之间的相互调用,利人利己。
2Node中的模块化
分为三大模块,内置模块(fs,path,http前面已经讲过,因此不再赘述),自定义模块(主讲),第三方模块(包的概念)。
const fs=require('fs')
const custom=require('./custom.js')
const moment=require('moment')
其中我们需要注意的是在自定义模块中的变量方法,只能被当前模板内访问。因此叫做模块作用域,其实和函数作用域类似。好处是防止了全局变量污染的问题。

然后再来讨论自定义模块,在每个自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息。在自定义模块中,可以使用module.export对象,把模块内的成员共享出去,供外界使用。外界用require()方法导入自定义模块时,得到的就是module,exports所指向的对象。就下面代码为例,即使你给module挂载了多个属性,但是最终永远以module.exports所指向的对象为准。
// 在一个自定义模块中,默认情况下, module.exports = {}
const age = 20
// 向 module.exports 对象上挂载 username 属性
module.exports.username = 'zs'
// 向 module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function() {
console.log('Hello!')
}
module.exports.age = age
// 让 module.exports 指向一个全新的对象
module.exports = {
nickname: '小黑',
sayHi() {
console.log('Hi!')
}
}
const m = require('./11.自定义模块')
console.log(m)//{ nickname: '小黑', sayHi: [Function: sayHi] }
以下演示4段代码,更加清晰的明确其中的关系。
exports.username = 'zs'
module.exports = {
gender: '男',
age: 22
} //{gender:'男',age:22}
module.exports.username = 'zs'
exports = {
gender: '男',
age: 22
} //{username:'zs'}
exports.username = 'zs'
module.exports.gender = '男' //{username:'zs',gender:'男'}
exports = {
username: 'zs',
gender: '男'
}
module.exports = exports
module.exports.age = '22' //{username:'zs',gender:'男',age:'22'}
因此为了防止混乱,最好不要在一个JS文件中,同时用exports和module.exports
CommonJS规定:每个模块内部,module变量代表当前模块。它的属性exports是对外的接口,加载某个模块,实际上是加载该模块的module.exports属性,用require方法加载模块。
第三方模块又称为包。包是基于Node内置模块封装出来的,类似于jQuery是基于浏览器内置API一样的关系。那么包有什么用呢?下面放一段代码用来格式化时间。一种方法是自定义模块,另一种方法是采用包moment,具体用法可以参考API官方文档
// 1. 定义格式化时间的方法
function dateFormat(dtStr) {
const dt = new Date(dtStr)
const y = dt.getFullYear()
const m = padZero(dt.getMonth() + 1)
const d = padZero(dt.getDate())
const hh = padZero(dt.getHours())
const mm = padZero(dt.getMinutes())
const ss = padZero(dt.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
// 定义补零的函数
function padZero(n) {
return n > 9 ? n : '0' + n
}
module.exports = {
dateFormat
}
// 导入自定义的格式化时间的模块
const TIME = require('./15.dateFormat')
// 调用方法,进行时间的格式化
const dt = new Date()
console.log(dt)//2021-07-22T11:55:39.349Z
const newDT = TIME.dateFormat(dt)
console.log(newDT)//2021-07-22 19:54:24
// 1. 导入需要的包
// 注意:导入的名称,就是装包时候的名称
const moment = require('moment')
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)
需要注意的是我们需要的第三方包和内置模块都是放在node_modules里面的,因此在我们拿到别人的项目后,需要使用nmp install命令,下载node_modules里面的所有内容,因为别人给的项目里面是不会包含node_modules这个文件夹的,所以我们需要自己下载。
3模块的加载机制
模块在第一次加载后会被缓存,这也意味着多次调用require不会导致模块的代码被执行多次。他们都会优先从缓存中加载,从而提高模块的加载效率。并且内置模块的优先级更高,也就是说即使我们自定义模块名为fs 实际上使用的还是内置模块fs。
对于自定义模块的加载机制,如果require时省略了文件的扩展名,则node会尝试js,json,node这三种扩展名进行加载,如果找不到就会报错。
对于第三方模块的加载机制,如果在当前模块的父目录下没有找到对应的文件,则会移动到再上一层父目录中,进行加载。直到找到根目录

本文详细介绍了Node.js中的模块化概念,包括内置模块、自定义模块的模块作用域与导出机制,以及第三方模块(包)的使用和加载流程。重点讲解了如何避免混淆并有效管理模块间的交互。
1109

被折叠的 条评论
为什么被折叠?



