模块化演进过程

演进过程

全局function模式: 将不同的功能封装成不同的全局函数

  • 编码: 将不同的功能封装成不同的全局函数

  • 问题: 污染全局命名空间, 容易引起命名冲突或数据不安全,而且模块成员之间看不出直接关系

1
2
3
4
5
6
function m1(){
//...
}
function m2(){
//...
}

namespace 模式: 简单对象封装

  • 作用: 减少了全局变量,解决命名冲突

  • 问题: 数据不安全(外部可以直接修改模块内部的数据)

1
2
3
4
5
6
7
8
9
10
11
let myModule = {
data: 'www.baidu.com',
foo() {
console.log(`foo() ${this.data}`)
},
bar() {
console.log(`bar() ${this.data}`)
}
}
myModule.data = 'other data' //能直接修改模块内部的数据
myModule.foo() // foo() other data

这样的写法会暴露所有模块成员,内部状态可以被外部改写。

IIFE模式:匿名函数自调用(闭包)

  • 作用: 数据是私有的, 外部只能通过暴露的方法操作

  • 编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口

  • 问题: 如果当前这个模块依赖另一个模块怎么办?

1
2
3
4
5
6
7
8
9
// index.html文件
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
myModule.foo()
myModule.bar()
console.log(myModule.data) //undefined 不能访问模块内部数据
myModule.data = 'xxxx' //不是修改的模块内部的data
myModule.foo() //没有改变
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// module.js文件
(function(window) {
let data = 'www.baidu.com'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(`foo() ${data}`)
}
function bar() {
//用于暴露有函数
console.log(`bar() ${data}`)
otherFun() //内部调用
}
function otherFun() {
//内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.myModule = { foo, bar } //ES6写法
})(window)

IIFE模式增强: 引入依赖

这就是现代模块实现的基石

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// module.js文件
(function(window, $) {
let data = 'www.baidu.com'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(`foo() ${data}`)
$('body').css('background', 'red')
}
function bar() {
//用于暴露有函数
console.log(`bar() ${data}`)
otherFun() //内部调用
}
function otherFun() {
//内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.myModule = { foo, bar }
})(window, jQuery)
1
2
3
4
5
6
7
// index.html文件
<!-- 引入的js必须有一定顺序 -->
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
myModule.foo()
</script>

上例子通过jquery方法将页面的背景颜色改成红色,所以必须先引入jQuery库,就把这个库当作参数传入。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显

模块化的好处

  • 避免命名冲突(减少命名空间污染)

  • 更好的分离, 按需加载

  • 更高复用性

  • 高可维护性

引入多个