模块化是标准,不是实现
什么是前端模块化
- 复杂的程序根据规范拆成若干,一个模块中包含输入、输入
- 模块内部私有化,对外暴露接口与其它模块进行通信
脚本和模块的区别
- 脚本 都在一个js文件中
- 模块 有入口文件,引入不同的模块,代码上更易读
模块化进化过程
1. 全局function函数,不同功能封装不同函数
- *缺陷:全局直接挂在到window上,容易引发全局命名冲突
2. 全局namepace模块,通过对象封装模块
window.__module = {
var a = 1;
handle() {}
}
缺陷: 外部能修改对象中的变量
3. IIFE模式,自执行函数创建闭包
(function() {
var x = 1;
function handle() {
};
function getX() {
return x
};
function setX(v) {
x = v
}
window.__module = {
x,
handle,
setX,
getX
}
})()
缺陷: 模块无法互相通信
- 函数作用域内变量和对象属性值的区别
const m = window.__module
console.log(m.x) // 1(相当于将函数作用域内的变量x,拷贝到对象中,生成一个新的属性x)
console.log(m.getX()) // 1
m.setX(2)
console.log(m.x) // 1
console.log(m.getX()) // 2
4. IIFE模式增强,支持传入自定义依赖
缺陷:
- 多依赖传入,代码阅读困难
- 无法支持大规模的模块化开发
- 无特定语法支持,代码简陋
// test-api.js
(function(global) {
var x = 1
function setX(v) {
x = v
}
function getX() {
return x
}
global.__module_API = {
x,
setX,
getX
}
})(window)
// test-sum.js
(function(global, api) {
function sum(a, b) {
return a+b
}
global.__module = {
api,
sum
}
})(window, window.__module_API)
const m = window.__module
console.log('x', m.api.x);
console.log('getX', m.api.getX());
m.api.x = 2
m.api.setX(3)
console.log('x', m.api.x);
console.log('getX', m.api.getX());
<!-- test.html -->
<html>
<header>
<script src="./test-api.js"></script>
<script src="./test-sum.js"></script>
</header>
</html>
commonJS规范特点
- 所有代码都运行在模块作用域,不会污染全局作用域。
- 模块可以多次加载,第一次加载时会运行模块,模块输出结果会被缓存,再加载时,会从缓存中直接读取模块。
- 模块的加载顺序,按照其在代码中出现的顺序进行加载。
- 模块输出的值 是值的拷贝,类似IIFE方案中的内部变量。
// 导出
function test() {
return 123
}
module.exports = {
test
}
//导入
const {test} = require(‘./test.js)
⚠️ module.exports 会覆盖 exports 的导出
commonJS打包
browserify <文件path> -o <打包后path>
browserify打包原理
- 本质 通过自执行函数实现模块化。
- 将每个模块编号 存入一个对象 每个模块标记依赖模块。
- 实现了require方法,核心 通过call方法调用模块,传入require、module、exports方法,通过module存储模块信息,通过exports存储模块输出信息。
AMD规范
- 非同步加载模块,允许指定回调函数。
- node模块通常位于本地,加载速度快,适用于同步加载。
- 浏览器环境下,模块需要请求获取,所以适用于异步加载。
- require.js 是AMD的一个具体实现库
CMD规范
整合了commonJS和AMD的优点
ESModule规范介绍
设计理念是希望在编译时就确定模块依赖关系及输入输出。
commonJS和AMD必须运行时才能确定依赖和输入、输出。
ESModule import加载模块 export输出模块
commonJS和ESModule规范对比
- commonJS模块输出是值的拷贝,ESModule模块输出是值的引用。
- commonJS模块是运行时加载,ESModule模块输出是值的引用。
- commonJS是单个值导出,而ESModule可以导出多个(
import * as echarts from ‘echarts’
类似这种导出多个) - commonJS是同步加载,ESModule支持异步加载(
import(模块).then(res => {})
) - commonJS this指向当前模块(
this === module.exports //true
),ESModule this指向undefined
脚本和模块对比
- 模块具备更高开发效率(可读性强,复用高效)
- 脚本具有更高的页面性能(模块文件多,加载速度慢)
- ⚠️模块在浏览器中运行会存在兼容性问题
浏览器模块化的局限
- 缺乏模块管理,模块分散在各个项目中
- 性能加载慢,大型项目无法直接使用
- ⚠️npm和webpack解决以上两个问题