随着前端应用的日益复杂,我们的项目变得越来越复杂且难以管理。而模块化就是一种最主流的代码组成方式,通过把复杂的代码按照功能的不同划分成不同的模块,进行单独维护,而提高效率,降低维护成本。模块化经历了以下几个时期:
1、Stage 1- 文件划分方式
具体做法就是将每个功能及相关状态数据各自单独放到不同的文件中,约定每个文件就是一个独立的模块,使用这个模块就是将这个模块引入到页面当中,然后直接调用模块中的成员(变量/函数)。
// module-a.js
var name = 'module-a'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
// module-b.js
var name = 'module-b'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
2、Stage 2- 命名空间
每个模块只暴露一个全局对象,所有模块成员都挂载到这个对象中。就是在第一阶段的基础上,通过将每个模块「包裹」为一个全局对象的形式实现,有点类似于为模块内的成员添加了「命名空间」的感觉,可以减少命名冲突的可能。但是这种方法仍然没有私有空间,内部成员仍然可以被外部修改,另外模块之间的关系也没有得到解决。
// module-a.js
var moduleA = {
name: 'module-a',
method1: function () {
console.log(this.name + '#method1')
},
method2: function () {
console.log(this.name + '#method2')
}
}
// module-b.js
var moduleB = {
name: 'module-b',
method1: function () {
console.log(this.name + '#method1')
},
method2: function () {
console.log(this.name + '#method2')
}
}
3、Stage 3-IIFE
使用立即执行函数表达式(IIFE:Immediately-Invoked Function Expression)为模块提供私有空间,具体做法就是将每个模块成员都放在一个函数提供的私有作用域中,对于需要暴露给外部的成员,通过挂在到全局对象上的方式实现。
// module-a.js
;(function () {
var name = 'module-a'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
window.moduleA = {
method1: method1,
method2: method2
}
})()
// module-b.js
;(function ($) {
var name = 'module-b'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
window.moduleB = {
method1: method1,
method2: method2
}
})(jQuery)
匿名函数实现了私有成员的概念,模块内部的私有成员只能通过闭包的形式被访问,不能被外部直接访问和修改,而且可以利用自执行函数的参数作为依赖声明去使用。
以上的方式都是以原始的模块系统为基础,通过约定的方式实现模块化代码组织,这些方式在不同的开发者去实施的时候会有一些差别,为了统一不同的开发者和不同项目之间的差异,我们需要一个标准去规范模块化实现方式。另外上述方式的模块加载都是通过script标签手动引入,这样不利于后期维护。我们需要基础的公共代码去实现自动通过代码去加载模块。所以我们需要一个模块化标准和一个模块加载器。
文章内容输出来源:拉勾教育大前端高薪训练营。