table of contents

1概述

INFO

本书所指的模块,都是代码模块,而非业务功能模块。

我们在前面学习了很多方法,用于拆分代码的规模。例如把一段逻辑封装为函数,把一些实例提炼成为类。

我们在用很多方式把一个大的问题,化解为小的问题。

模块化,就是在这种思路下提炼出来的工程化解决方案。因此,我们可以在一定的规范之下,引入别人已经封装好的模块用于解决自己的问题,而不需要自己重复封装。

模块最核心的思想是隔离。要有自己的内部属性,内部方法,以及自己来决定哪些属性与方法能够被其他模块访问。但是 JavaScript 在最初并没有模块相关的支持语法。因此我们只能利用许多别的类似的,具备隔离属性的方式来模拟模块。

2模块的发展历程

了解模块发展历程有助于增加我们的知识厚度。目前在实践中,我们仅使用最新的模块化语法。

1、函数自执行

因为没有模块化语法,我们常常用自执行函数来模拟模块。

code.ts
1
// 自执行函数模拟模块化
2
3
// Person 模块
4
(() => {
5
// 实例个数,模块内部变量,外部无法直接访问,
6
let number = 0
7
function Person(name, age) {
8
number ++
9
this.name = name
10
this.age = age
11
}
12
13
Person.prototype.getName = function() {
14
return this.name
15
}
16
17
Person.getInstanceNumber = function() {
18
return number
19
}
20
21
// 对外抛出接口
22
window.Person = Person
23
})();
24
25
26
// main 模块
27
(() => {
28
// 引入模块
29
const Person = window.Person
30
31
const p1 = new Person('Tom', 20)
32
const p2 = new Person('Jake', 20)
33
const p3 = new Person('Alex', 20)
34
35
p1.getName()
36
37
console.log('实例化个数', Person.getInstanceNumber())
38
})()

3CommonJS 规范

Node 应用的模块,就是采用 CommonJS 规范来实现。

在 nodejs 中,每一个文件就是一个模块,有自己的作用域。因此,在该文件中,定义的变量、函数、类都是私有的。

每个模块内部,module 用于代表当前模块。

并且使用 module.exports 对外暴露接口。

在其他模块,可以使用 require 加载该模块,加载的结果,就是 module.exports 的合集。

code.ts
1
// person 模块
2
// person.js
3
let number = 0
4
function Person(name, age) {
5
number++
6
this.name = name
7
this.age = age
8
}
9
10
// 对外暴露接口
11
Person.prototype.getName = function () {
12
return this.name
13
}
14
15
// 对外暴露接口
16
module.exports.getInstanceNumber = function () {
17
return number
18
}
19
module.exports.Person = Person
code.ts
1
// main.js
2
// 引入模块
3
const person = require('./person.js')
4
5
const {Person, getInstanceNumber} = person
6
7
const p1 = new Person('Tom', 20)
8
const p2 = new Person('Jake', 20)
9
const p3 = new Person('Alex', 20)
10
11
p1.getName()
12
p2.getName()
13
p3.getName()
14
15
console.log('实例化个数', getInstanceNumber())
16

4AMD

AMD 是适用于浏览器环境的异步加载模块规范,它是一种依赖前置的规范。

INFO

依赖前置:所有的 require 都会提前执行

require.jscurl.js 实现了该规范。该规范使用 define 定义一个模块

code.ts
1
// person.js
2
define(function() {
3
let number = 0
4
function Person(name, age) {
5
number++
6
this.name = name
7
this.age = age
8
}
9
10
// 对外暴露接口
11
Person.prototype.getName = function () {
12
return this.name
13
}
14
15
function getInstanceNumber() {
16
return number
17
}
18
19
// 对外暴露接口
20
return {
21
getInstanceNumber,
22
Person
23
}
24
})
code.ts
1
// main.js
2
// 引入模块
3
define(['./person.js'], function(person) {
4
const { Person, getInstanceNumber } = person
5
6
const p1 = new Person('Tom', 20)
7
const p2 = new Person('Jake', 20)
8
const p3 = new Person('Alex', 20)
9
10
p1.getName()
11
p2.getName()
12
p3.getName()
13
14
console.log('实例化个数', getInstanceNumber())
15
})
16

5CMD

CMD 规范是模仿 CommonJS,由阿里玉伯提出,sea.js 实现了该规范,这是一种就近依赖的规范

INFO

就近依赖:下载完之后,并不执行加载,回调函数中遇到 require 时才执行

code.ts
1
// person.js
2
define(function(require, exports, module) {
3
let number = 0
4
function Person(name, age) {
5
number++
6
this.name = name
7
this.age = age
8
}
9
10
// 对外暴露接口
11
Person.prototype.getName = function () {
12
return this.name
13
}
14
15
// 对外暴露接口
16
module.exports.getInstanceNumber = function () {
17
return number
18
}
19
module.exports.Person = Person
20
})
code.ts
1
2
// mian.js
3
define(function(require) {
4
const person = require('./person.js')
5
const { Person, getInstanceNumber } = person
6
7
const p1 = new Person('Tom', 20)
8
const p2 = new Person('Jake', 20)
9
const p3 = new Person('Alex', 20)
10
11
p1.getName()
12
p2.getName()
13
p3.getName()
14
15
console.log('实例化个数', getInstanceNumber())
16
})

6UMD

UMD 是一个兼容写法,一个开源模块可能会提供给 CommonJS 标准的项目中实现,也可能提供给 AMD 标准的项目使用。UMD 应运而生。

code.ts
1
(function(root, factory) {
2
if (typeof define === 'function' && define.amd) { // AMD
3
define(['person'], factory)
4
} else if (typeof define === 'function' && define.cmd) { // CMD
5
define(function(require, exports, module) {
6
module.exports = factory()
7
})
8
} else if (typeof exports === 'object') { // CommonJS
9
module.exports = factory()
10
} else { // global
11
root.person = factory()
12
}
13
})(this, function() {
14
let number = 0
15
function Person(name, age) {
16
number++
17
this.name = name
18
this.age = age
19
}
20
21
// 对外暴露接口
22
Person.prototype.getName = function () {
23
return this.name
24
}
25
26
function getInstanceNumber () {
27
return number
28
}
29
30
return {
31
Person,
32
getInstanceNumber
33
}
34
})

很多开源模块都会采用这种兼容性的写法。

7ES6 Modules

ES6 提出了新的模块化语法规范。

这也是目前我们在实践开发中,使用得最多的规范。

code.ts
1
// person.js
2
let number = 0
3
export function Person(name, age) { // 暴露接口
4
number++
5
this.name = name
6
this.age = age
7
}
8
9
// 对外暴露接口
10
Person.prototype.getName = function () {
11
return this.name
12
}
13
14
// 对外暴露接口
15
export const getInstanceNumber = function () {
16
return number
17
}
code.ts
1
// main.js
2
// 引入模块
3
import {Person, getInstanceNumber} from './person.js'
4
5
const p1 = new Person('Tom', 20)
6
const p2 = new Person('Jake', 20)
7
const p3 = new Person('Alex', 20)
8
9
p1.getName()
10
p2.getName()
11
p3.getName()
12
13
console.log('实例化个数', getInstanceNumber())
专栏首页
到顶
专栏目录