前言:
模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将如何影响其它部分就会变得显而易见,系统的可维护性更加简单易得。
前端开发领域(JavaScript、CSS、Template)并没有为开发者们提供以一种简洁、有条理地的方式来管理模块的方法。CommonJS(致力于设计、规划并标准化 JavaScript API)的诞生开启了“ JavaScript 模块化的时代”。CommonJS 的模块提案为在服务器端的 JavaScript 模块化做出了很大的贡献,但是在浏览器下的 JavaScript 模块应用很有限。随之而来又诞生了其它前端领域的模块化方案,像 requireJS、SeaJS 等,然而这些模块化方案并不是十分适用 ,并没有从根本上解决模块化的问题。
模块化的理解:
前端模块化并不等于 JavaScript 模块化,JavaScript 模块化并不等于异步模块化。
模块的含义:
- 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。
- 块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
模块化的进化过程:
- 全局function模式 : 将不同的功能封装成不同的全局函数
处理:将不同的功能封装成不同的全局函数;
作用:以方法形式封装分离功能;
弊端:污染全局命名空间, 容易引起命名冲突或数据不安全,而且模块成员之间看不出直接关系;
function fn1(){
...
}
function fn2(){
...
}
- namespace模式 : 简单对象封装
处理:以对象方式封装相应功能模块;
作用:减少了全局变量,解决命名冲突;
弊端:数据不安全,暴露所有模块成员,内部状态可以被外部改写;
let module= {
data: 'natsu',
foo() {
console.log(this.data);
}
}
module.data = 'cc' //能直接修改模块内部的数据
module.foo() // cc
- IIFE模式:匿名函数自调用(闭包)
处理:将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口;
作用:数据是私有的, 外部只能通过暴露的方法操作;
弊端:模块依赖问题。
// index.html文件
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
module.foo() //natsu
console.log(module.data) //undefined 不能访问模块内部数据
module.data = 'cc' //不是修改的模块内部的data
module.foo() //natsu 没有改变
</script>
// module.js文件
(function(window) {
let data = 'natsu'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(data)
}
//暴露行为
window.module= {
foo } //ES6写法
})(window)
- IIFE模式增强 : 引入依赖
作用:保证模块的独立性,使得模块之间的依赖关系变得明显。
// index.html文件
<!-- 引入的js必须有一定顺序(保证依赖关系) -->
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
module.foo() //natsu
</script>
// module.js文件
(function(window, $) {
let data = 'natsu'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(data)
$('body').css('background', 'red')
}
//暴露行为
window.module= {
foo }
})(window, jQuery)
模块化的好处:
- 避免命名冲突(减少命名空间污染)
- 更好的功能代码分离, 按需加载
- 更高复用性
- 高可维护性
模块化的弊端:
- <script>引入导致请求过多
- 依赖关系模糊
- 难以维护
把所有需要加载的模块按顺序一一加载完毕,当模块很多、依赖关系复杂的情况下会严重影响页面性能,因此我们模块化也需要一定的规范进行约定。
模块化规范:
CommonJS:
概述:
Node 应用由模块组成,采用 CommonJS 模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理。
特点:
- 所有代码都运行在模块作用域,不会污染全局作用域。
- 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要让模块再次运行,就需要清除缓存。
- 模块加载的顺序,按照其在代码中出现的顺序。
基本语法:
- 暴露模块:module.exports = value或exports.xxx = value。
- 引入模块&