模块化
啥是模块化?
一个js文件可以引入其他的js文件,能使用引入的js文件的中的变量、数据,这种特性就称为模块化。
使用模块化开发可以很好的解决变量、函数名冲突问题,也能灵活的解决文件依赖问题。
模块化的发展
● 以前
es5不支持模块化,让前端人员很为难。为了让支持模块化,我们一般会借用第三方库来实现:
○ sea.js. https://www.zhangxinxu.com/sp/seajs/
○ require.js. https://requirejs.org/
● 现在
○ es6原生语法也支持模块化(并不表示浏览器也直接支持模块化 — 需要单独设置一下)
○ Nodejs内部也支持模块化(与es6的模块化有些不同之处),具体的语法在后面来介绍。
常见的模块化规范有
● CommonJS 规范(nodejs 默认支持的)
● ES6 模块化规范
● CMD 和 AMD 模块化规范(不再推荐使用)
模块分类
nodejs模块的分类
● 核心模块
○ 就是nodejs自带的模块,在安装完nodejs之后,就可以随意使用啦。相当于学习js时使用的Array对象。
○ 例:fs, http, querystring, path
○ 全部模块的源代码 https://github.com/nodejs/node/tree/master/lib
● 自定义模块
○ 程序员自己写的模块。就相当于我们在学习js时的自定义函数。
● 第三方模块
○ 其他程序员写好的模块。nodejs生态提供了一个专门的工具npm来管理第三方模块,后面我们会专门讲到。
○ 相当于别人写好的函数或者库。例如我们前面学习的JQuery库,arttemplate等。
自定义模块
我们对代码的封装是以模块(一个独立的.js文件)为单位进行的。一般的做法是实现好某一个功能之后,封装成一个模块,然后在其它文件中使用这个模块。
类比于js自定义函数,自定义模块的使用场景是:
● 代码需要在项目重用
● 代码需要提供给他人使用
● 代码虽然不需要重用,但封装成模块有利于优化代码结构,方便后期维护与扩展
步骤
一共有两步:
- 定义模块。就是创建一个js文件, 对外导出我们希望导出的内容。
- 使用模块。在需要使用的地方去导入模块文件。
Node.js 中的 CommonJS 的模块化规范
CommonJS 规范中主要规定了以下 3 项内容:
● 导入其它模块时,统一使用 require() 函数。
注意这里使用的是相对路径。可省略.js.
const tool = require(‘./tool.js’)
● 每个 .js 文件,都是一个独立的模块,模块内的成员都是私有的。
● 在每个 JS 模块中,使用 module.exports 向外共享成员。
根目录
├── user.js # 定义模块
└── test.js # 引入user.js模块
注意
● module.exports 是固定写法,一般放在文件的最末尾,也只用一次。
● module.exports表示当前模块要暴露给其它模块的功能。
○ 它可以导出对象,数组,函数等等类型。为了方便组织代码,导出对象的情况比较多。
○ 不必要导出所有函数,对象,数组等。那些没有导出的部分就相当于这个模块的内部变量了。在下图中变量1,函数1,变量2就是模块内部的数据,在外部无法别访问到。
小结
所谓定义模块,就是新建一个js文件。文件取名时,要注意一下:
● 一般会用模块名给它命名。类比于核心模块,例如,你的模块叫myModule,则这个js文件最好叫myModule.js
● 不要与核心模块的名字重复了。就像我们定义变量不要与核心关键字重名,你自己定义的模块也不要叫fs.js,因为nodejs有一个核心模块就叫fs.js。
● 要记得导出模块
导出模块的两种方式
● exports
● module.exports
// 定义方法,常量
const myPI = 3.14
const add = (a,b) => a + b;
// 导出,两种方法任意都可以
// 方法一:
exports.myPI = myPI
exports.add = add
// 方法二:
module.exports.myPI = myPI
module.exports.add = add
// 方法二(变形)
module.exports = {
myPI,
add
}
两个对象的关系
初始时:
初始exports和module.exports是指向同一块内存区域,其内容都是一个空对象。
exports === module.exports // 输出是 true
在定义模块时:
如果直接给exports对象赋值(例如:exports={a:1,b:2}),此时,exports就不会再指向module.exports,而转而指向这个新对象,此时,exports与module.exports不是同一个对象(存在两个不同对象)
在引入某模块时:以该模块代码中module.exports指向的内容为准。
只有点语法是向原本的空对象中添加键值对
在导出模块过程中,建议只用一种方式(建议直接使用module.exports)