# 原生 JavaScript 模块化
# 反模式
反模式指没有使用任何模块系统,把不同的函数放到一起就算是一个模块:
function f1() {
//...
}
function f2() {
//...
}
1
2
3
4
5
6
2
3
4
5
6
缺点:
- 污染了全局变量,无法保证不和其他模块发生变量命名冲突
- 模块成员之间看不出直接关系
# 字面量
为了解决上面的缺点,可以把模块写成一个字面量,所有模块成员都放到这个对象中:
var module1 = new Object({
_count: 0,
f1: function() {
//...
},
f2: function() {
//...
}
});
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
但是这种写法会暴露所有模块成员,内部状态可以被外部改写。
# IIFE
使用立即执行函数可以解决上面的问题:
var module1 = (function() {
var _count = 0;
var f1 = function() {
//...
};
var f2 = function() {
//...
};
return {
f1: f1,
f2: f2
};
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
这样外部就无法读取内部状态。
# 传参
如果一个模块需要继承另一个模块,则需要传参:
var module1 = (function(mod) {
mod.m3 = function() {
//...
};
return mod;
})(window.module1 || {});
1
2
3
4
5
6
2
3
4
5
6
# 命名空间
//math.js
namespace("math", [], function() {
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
return {
add: add,
sub: sub
};
});
//calculator.js
namespace("calculator", ["math"], function(m) {
var action = "add";
function compute(a, b) {
return m[action](a, b);
}
return {
compute: compute
};
});
var namespace = (function() {
//缓存所有模块
var cache = {};
function createModule(
name /*模块名*/,
deps /*依赖列表*/,
definition /*定义*/
) {
//如果只有模块名,则直接输出
if (arguments.length === 1) {
return cache[name];
}
//取得所有模块的依赖
deps = deps.map(function(depName) {
return namespace(depName);
});
//初始化模块并返回
cache[name] = definition.apply(null, deps);
return cache[name];
}
return createModule;
})();
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 总结
模块依赖还是需要 amd cmd es6 moudlue 解决