模块化规范
什么是模块化?
- 模块化就是把单独的一个功能封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块;
- 将一个项目拆分为若干块,每块之间以一定的形式进行通信,而每块内部的内容都是独立的;
模块化的好处?
- 抽离公共的代码,提高了代码的维护性和复用性;
- 隔离作用域,避免变量的冲突;
- 将一个复杂的系统分解为多个子模块,便于开发和维护;
常用的模块化规范?
CommonJs
nodejs使用的commonJs规范;在nodejs中,有且仅有一个入口文件(启动文件),而开发一个应用肯定会涉及多个文件配合,因此,nodejs对模块化的需求比浏览器端要大得多;
特点
- CommonJs最大的特点就是同步加载;(缺点)
- 每一个文件都是一个Module对象,通过关键字module.exports或者exports来暴露内容,并可以通过require来引入指定模块;
- 模块一旦加载一次之后就会被缓存;
工作环境
服务端;两个原因使CommonJs无法在浏览器端使用:
- 根本原因:CommonJs中使用了Node的api,无法在浏览器中运行。
- 直接原因:作为一门同步加载的模块规范必须得在require完全加载好之后才能执行下一步,所以会有阻塞的情况,在网络状态比较差的情况下,就会导致浏览器的假死现象。(对于服务端,require的等待时间是硬盘读取时间,而对于浏览器端来说,这取决于网速的快慢。)
使用
- 使用
exports.x
或者module.exports
暴露模块;exports
是一个空对象==>exports={}
- 通过
require
来完成对模块的引入; - 如果一个JS文件存在
exports
或require
,该JS文件就是一个模块,拥有独立的作用域;
使用exports.x
暴露;
使用
exports.x
暴露;
1 | // 新建m1.js文件 |
使用
require
引入m1.js
;
1 | // 新建index.js文件用来引入m1.js |
使用module.exports
暴露多个;
使用
module.exports
暴露;在一个自定义模块中,默认情况下,module.exports={};
1 | // 新建m2.js文件 |
使用
require
引入m2.js
;
1 | // 两种方式的引入方式都是一样的,都是require("相对路径"); |
使用module.exports
暴露单个;
使用
module.exports
暴露;
1 | // 新建m2.js文件 |
使用
require
引入m2.js
;
1 | const M2 = require("./m2.js"); |
module.exports与exports有什么关系或者区别呢?
- 我们追根溯源,通过维基百科中对CommonJS规范的解析:
- CommonJS中是没有module.exports的概念的;
- 但是为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是
module; - 所以在Node中真正用于导出的其实根本不是exports,而是module.exports;
- 因为module才是导出的真正实现者;
- 但是,为什么exports也可以导出呢?
- 这是因为module对象的exports属性是exports对象的一个引用;
- 也就是说 module.exports = exports = index.js中的M2;
module对象
Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是module;
module.exports 对象
module.exports=xxx的过程其实是引用赋值(浅拷贝)的过程;exports(也是一个对象)之所以可以导出,就是把exports对象的地址赋值给了module.exports,借助module.exports导出;
- 使用 require() 方法导入模块时,导入的结果,永远以 最下面的module.exports 指向的对象为准;
1 | // 新建m2.js文件 |
1 | const M2 = require("./m2.js"); //require函数的返回值是个对象,是module.exports对象; |
- 上面的module.exports属性要是在下面结果就不一样了;相当于在原来的对象上添加了属性;
1 | // 新建m2.js文件 |
1 | const M2 = require("./m2.js"); //require函数的返回值是个对象,是module.exports对象; |
- exports与module.exports同时导出
由于真正用于导出的其实根本不是exports,而是module.exports;所以同时导出的时候module.exports开辟了新的内存地址,exports就相当于被架空了;
1 | // 新建m2.js文件 |
1 | const M2 = require("./m2.js"); //require函数的返回值是个对象,是module.exports对象; |
ES6
特点
- ES6最大的特点是按需加载;
工作环境
- 是浏览器端与服务器端通用的模块化开发规范;
使用
- 目前浏览器使用如下方式引入一个ES6模块文件:
<script src="入口文件" type="module"></script>
- 使用
export
或者export default
暴露模块; - 通过
import
来完成对模块的引入; export defalut
每个js模块里面只能有一个;export
可以有多个;
使用export
直接导出
使用
export
暴露;
1 | // 新建m1.js文件 |
使用
import {xx,xx} from "xxx"
引入;
1 | // 新建index.js文件用来引入m1.js |
使用export
一起导出
使用
export{}
暴露;
1 | // 新建m1.js文件 |
使用
import {xx,xx} from "xxx"
引入;
1 | // 新建index.js文件用来引入m1.js |
使用export default
导出
使用
export default
暴露;
1 | // 新建m1.js文件 |
使用
import xxx from "xxx"
引入;
1 | // 新建index.js文件用来引入m1.js |
混用
使用
export
和export default
暴露;
1 | // 新建m1.js文件 |
使用
import xxx,{xx,xx} from "xxx"
引入;
1 | // 新建index.js文件用来引入m1.js |
参考文献
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Forward の Blog!
评论