前端工程化-模块化-初识模块化

140 阅读4分钟

先通过几个问题,认识一下模块化。(本文仅针对前端开发者,语言也仅限Javascript。)

什么是模块化?

回答这个问题之前,我们可以先举几个例子:

比如,我们需要开发一个大型用户管理类的web应用,在JS逻辑部分,需要大概10w行代码,其中可能包括很多功能不同的代码模块。类似:用户信息模块、交易账户模块等等。

最简单粗暴的方式就是把所有的JS代码写到一个文件中(10w行的JS文件,例子稍微有点极端),这一定能跑起来,但是,这代码还能维护么?存在的问题大体如下:

  • 代码量多,一眼看不到边
  • 所有代码共用一个作用域,很容易命名冲突
  • 如果代码组织的不够好,代码的耦合性很可能越来越高

所以,如果我们能够按照每段代码的原本职责,按照不同的功能模块进行拆分,最终再将他们合并起来,就能解决上面的问题了。

所谓模块化的概念,也就出现了。

即,将代码按照一定的原则,拆分成不同部分,独立维护开发,在使用的时候,进行组装。

为什么需要模块化?

这个问题其实可以反过来想,如果不用模块化会怎么样?其实也就是上一个问题局的那个例子出现的问题。使用模块化后的好处也就随之体现:

  • 避免命名冲突(减少命名空间污染)
  • 更好的分离,按需加载
  • 更高复用性(模块独立,实现复用)
  • 高可维护性(结构清晰易于维护)

模块化的实现方式

这里就得讲讲模块化的历史了。其实简单来说,就是一个发现问题,解决问题的过程,最终演化出最合适的方式。

最早,为了解决非模块化的问题之一,命名冲突,也就是共用统一作用域的问题。解法无非是划出子作用域来,那么很自然的能想到JS的“函数作用域”。

所以就出现了最原始的模块化解决方案,全局函数。

全局函数实现模块化

function user () { ... }
function account () { ... }

但这样做一样存在问题:文件代码量还是大;模块与模块之间看不出关联关系。

除此以外,还有没有办法能划出自作用域?当然,利用JS的对象数据结构,可以以命名空间的方式,划分出作用域。

对象命名空间实现模块化

var User = {
	name: 'Bob'
	login: function () { ... }
	logout: function () { ... }
}

这种方式一样,也存在全局函数实现方式相关的问题,同时还有一点,对象的属性是非私有的,可能被修改。

有没有什么方式,能够实现属性的私有化不被修改?很自然能够想到,利用函数闭包。函数自执行是个好办法。

自执行函数实现模块化

(function (window) {
	var name = 'Bob'
	function sayName () { console.log(name) }
	window.User = { sayName }
})(window)

User.sayName() // Bob

在自执行函数内,将模块暴露给window即可。

接下来还有个问题,如果User模块依赖别的模块怎么办?其实解法也比较简单,通过参数将依赖传进去就可以了。

// Account模块
(function (window) {
	var cash = 1000
	function getCash () { console.log(cash) }
	window.Cash = { getCash }
})(window)

(function (window, Cash) {
	var name = 'Bob'
	function sayName () { console.log(name) }
	function getUserCash () { Cash.getCash() }
	window.User = { sayName, getUserCash }
})(window, Cash)

User.getUserCash() // 1000

上述,基本上实现了模块化的思想。

代码独立、模块互相可依赖、模块作用域私有化。

可传依赖的自执行函数也是后续各种成熟模块化规范的基石!

我们还可以利用 script标签,将不同的模块分装在不同的JS文件中,用script标签引用,最终实现文件级别的隔离。

<script type="text/javascript" src="user.js"></script>
<script type="text/javascript" src="account.js"></script>

<script>
	User.getUserCash() // 1000
</script>

其实用script标签加载,也会有问题,一个是引用顺序很关键,不能错;二是请求过多。

所以,结合所有的问题,但核心以IIFE为基石,各种模块化规范应运而生。有 CommonJS、AMD、CMD 和 ES Module。

接下来会用几篇文章逐个详述。