什么是模块化?
- 模块化就是把单独的一个功能封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块;
- 将一个项目拆分为若干块,每块之间以一定的形式进行通信,而每块内部的内容都是独立的;
模块化的好处?
- 抽离公共的代码,提高了代码的维护性和复用性;
- 隔离作用域,避免变量的冲突;
- 将一个复杂的系统分解为多个子模块,便于开发和维护;
常用的模块化规范?
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let num = 10;
function sum(a,b){ return a+b }
class Animal{ constructor(){ this.age=10; } }
exports.num1=num; exports.sum=sum; exports.Animal=Animal;
|
使用 require
引入 m1.js
;
1 2 3 4 5 6 7 8 9 10
|
const M1 = require("./m1.js"); console.log(M1);
console.log(M1.num1); console.log(M1.sum(2,3));
const DOG = new M1.Animal(); console.log(DOG.age)
|
使用 module.exports
暴露多个;
使用 module.exports
暴露;在一个自定义模块中,默认情况下,module.exports={};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| let num = 10;
function sum(a,b){ return a+b }
class Animal{ constructor(){ this.age=10; } }
module.exports={ num, sum, Animal, }
|
使用 require
引入 m2.js
;
1 2 3 4 5 6 7 8 9
| const M2 = require("./m2.js"); console.log(M2);
console.log(M2.num); console.log(M2.sum(5,3));
const CAT = new M2.Animal(); console.log(CAT.age)
|
使用 module.exports
暴露单个;
使用 module.exports
暴露;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let num = 10;
function sum(a,b){ return a+b }
class Animal{ constructor(){ this.age=10; } }
module.exports=sum;
|
使用 require
引入 m2.js
;
1 2 3 4 5
| const M2 = require("./m2.js"); console.log(M2);
console.log(M2(5,3));
|
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let num = 10;
function sum(a,b){ return a+b }
module.exports.num=num; module.exports.sum=sum;
module.exports={ name:"开辟新的引用类型地址" }
|
1 2
| const M2 = require("./m2.js"); console.log(M2);
|
- 上面的 module.exports 属性要是在下面结果就不一样了;相当于在原来的对象上添加了属性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let num = 10;
function sum(a,b){ return a+b }
module.exports={ name:"开辟新的引用类型地址" }
module.exports.num=num; module.exports.sum=sum;
|
1 2
| const M2 = require("./m2.js"); console.log(M2);
|
- exports 与 module.exports 同时导出
由于真正用于导出的其实根本不是 exports,而是 module.exports;所以同时导出的时候 module.exports 开辟了新的内存地址,exports 就相当于被架空了;
1 2 3 4 5 6 7 8 9 10 11 12 13
| let num = 10;
function sum(a,b){ return a+b }
module.exports.num=num; module.exports.sum=sum;
exports={ name:"开辟新的引用类型地址" }
|
1 2
| const M2 = require("./m2.js"); console.log(M2);
|
ES6
特点
工作环境
使用
- 目前浏览器使用如下方式引入一个 ES6 模块文件:
<script src="入口文件" type="module"></script>
- 使用
export
或者 export default
暴露模块;
- 通过
import
来完成对模块的引入;
export defalut
每个 js 模块里面只能有一个;export
可以有多个;
使用 export
直接导出
使用 export
暴露;
1 2 3
| export let name = "张三"; export let age = 12;
|
使用 import {xx,xx} from "xxx"
引入;
1 2 3 4
| import {name,age} from "./m1.js"; console.log(name); console.log(age);
|
使用 export
一起导出
使用 export{}
暴露;
1 2 3 4 5 6 7
| let name = "张三"; let age = 13; export { name, age }
|
使用 import {xx,xx} from "xxx"
引入;
1 2 3 4
| import {name,age} from "./m1.js"; console.log(name); console.log(age);
|
使用 export default
导出
使用 export default
暴露;
1 2 3 4 5 6 7
| let name = "张三"; let age = 14; export default{ name, age }
|
使用 import xxx from "xxx"
引入;
1 2 3 4 5 6
| import m1 from "./m1.js"; console.log(m1);
console.log(m1.name); console.log(m1.age);
|
混用
使用 export
和 export default
暴露;
1 2 3 4 5 6 7 8
| export let email = "nodeJs@163.com"; let name = "张三"; let age = 18; export default{ name, age }
|
使用 import xxx,{xx,xx} from "xxx"
引入;
1 2 3 4 5 6 7
| import m1,{email} from "./m1.js"; console.log(m1);
console.log(m1.name); console.log(m1.age); console.log(email);
|
参考文献