一、什么是模块化
模块化是在解决复杂问题的时候,把系统自顶向下拆分成若干模块的过程,对于整个系统来说,模块是可组合、分解和更换的单元。
编程中的模块化就是遵守固定的规则,把一个大文件拆分成独立且互相依赖的多个小模块。
1.模块化的好处:
- 提高了代码的可维护性
- 提高了代码的复用性
- 可以实现按需加载
2.模块化规范的规则:
使用统一的规则方便各大模块的互相调用(使用什么语法来引入或者向外暴露)
二.node.js中的模块化
1.node.js模块的分类
- 内置模块(fs、path、http)
- 自定义模块(用户创建的每个js文件都是自定义模块,js在node里跑就是自定义模块,在浏览器跑就是普通js文件。用module.exports、require这些都是遵循的node规则)
- 第三方模块(第三方开发出来的模块,使用之前需要先下载,npm的那些,什么axios、jquery这些都是)
内置和自定义的都在自己电脑上,第三方的就需要先下载才能使用,这是他们的区别
2.模块的加载
使用强大的require(),可以引入内置、自定义、第三方的模块进行使用
const fs=require('fs')
const clock=require('./clock.js')
const moment=require('moment')
只有自定义模块需要路径
使用require加载其他模块的时候,会执行被加载模块中的代码
使用require加载自定义模块的时候,js后缀可以省略
3.node.js的模块作用域
与函数作用域相似,模块作用域里定义的变量和方法只能在当前模块被访问,这种模块级别的访问限制叫模块作用域。(只能在自己文件访问自己的变量和方法)
模块作用域的好处:防止全局变量被污染
三.向外共享模块作用域中的成员
1.module对象
每个自定义模块都有一个module对象,他存储了当前模块有关的信息
比如我们随便创建一个js文件,然后打印一下它里面的module
console.log(module)

2.module.exports对象
从上面的截图可以看到exports默认是一个空对象,在自定义模块中,module.exports可以将模块中的成员共享出去供外界使用。然后外界使用require引入这个模块之后就可以拿到这个模块exports指向的对象。
module.exports默认是空对象,当module2文件里什么都没有的时候,a输出的是{},也就是mudule2中的module.exports对象
const a=require('./module2.js')
console.log(a)
如果我们想共享一些东西出去的话,就只需要给mudule2中的module.exports对象赋值即可,比如:
module.exports={
username:'hh',
sayHi(){
console.log('aa')
}
}
这里面写什么,require输出得到的就是什么,引入的文件输出:
我这里犯了一个错误,这里输出结果是aa undefined,我最开始纳闷undefined是哪来的,再一看发现console.log一个函数的话会先调用这个函数,然后打印出它的返回值
const a=require('./module2.js')
console.log(a.sayHi())
就等同于下面这样,运行完a.sayHi()(这个过程会输出aa),然后把结果赋值给了result(没有return就是undefined)然后输出
const a=require('./module2.js')
const result=a.sayHi()
console.log(result)
或者用module.exports.username='aa'这种方式赋值也可以
3.exports对象
由于module.exports对象写起来比较复杂,node提供了exports对象,默认情况下,exports对象就等同于module.exports,不过还是以module.exports指向的对象为准。
注意:require()得到的永远都是module.exports指向的对象
// Node.js 每个模块开始前,会悄悄执行这两行
var module = { exports: {} }
var exports = module.exports // exports 是 module.exports 的引用
所以像下面这个require得到的就是name 'hh',而不是那一大坨
module.exports.name='hh'
exports={
username:'hh',
sayHi(){
console.log('aa')
return '88'
}
}
在第一句执行完之后module.exports.name='hh',exports和module.exports都指向name 'hh'这个对象,然后下面的赋值让exports指向了别的对象,所以别的模块去require的时候得到的东西就跟exports无关了,所以建议不要在一个模块中用两种写法。
其实就只要记住这俩最开始指向一个对象,最后require得到的是module.exports指向的对象就可以了。
四.Node.js中的模块化规范
Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何互相依赖。
CommonJS规定:
- 每个模块内部,module变量代表当前模块
- module变量是一个对象,他的exports属性(即module.exports)是对外的接口
- 加载某个模块,其实是加载该模块的moudle.exports属性,require()方法用于加载该模块