理解模块化
模块化就是 把复杂的系统分解到多个模块以方便编码。
过去代码组织方式,会出现的问题:
- 命名空间冲突
- 无法合理地管理项目依赖和版本
- 无法方便控制依赖的加载顺序
- 项目体积变大后难以维护
模块化的发展
函数即模块
不同的函数声明,就是一个模块。
缺点:
- 污染全局变量,可能与其他模块发生变量名冲突
- 模块成员之间依赖关系,难以直接看出来 ```javascript function getUserList() {}
function updateUserName() {}
<a name="pbw7B"></a>## 对象即模块为了解决污染全局变量的问题,可以把模块写成一个对象,所有的模块成员都放到这个对象里面。<br />优点:1. 减少全局的变量数目2. 一定程度上,避免了变量名冲突缺点:1. 对象会暴露所有模块成员,内部状态可被外部改写。(模块成员是非私有的)```javascriptvar todo = {list: [],add: function() {},delete: function() {},}var user = {list: [],add: function() {},delete: function() {},}
立即执行函数(IIFE)
利用 IIFE 创建闭包,保存私有变量,只暴露给外部对应可访问的权限。
优点:
- 避免变量名冲突
- 拥有私有变量
缺点:
- 依赖情况依然不清晰
var todo = (function () {const list = []return {add: function (item) {list.push(item)},delete: function (index) { },get: function (index) { }}})()
IIFE 增强版(引入依赖)
IIFE 增强版:引入依赖
- 这就是现代模块实现的基石;
```javascript
var _fetch = (function () {
return function ({ method, url, data, callback }) {
return new Promise((resolve, reject) => {
}) } })()const XHR = new XMLHttpRequest();XHR.open(method, url)XHR.onload = function () {resolve(XHR.responseText)callback && callback(XHR.responseText)}XHR.send(data)
var todo = (function (dependencies) { const { _fetch } = dependencies
return {
getTodo: function (name) {
return new Promise((resolve, reject) => {
_fetch(‘get’, https://xxx?name=${name})
.then(res => {
resolve(res)
})
})
}
}
})({ _fetch })
<a name="dtgLu"></a># 模块化方案在**模块化编程**中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为 **模块**。<br />每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。<br />精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。- CommonJS- **同步加载** 依赖的模块- 可复用于 Node.js 环境 ,例如做同构应用- 成熟的第三方模块社区- 无法直接运行于浏览器环境,必须通过工具转换为标准的 ES5- AMD (Asynchronous Module Definition)- **异步加载** 依赖的模块- **并行** 加载多个模块- 可在不转换代码的情况下直接在 **浏览器** 运行- 可运行在浏览器和 Node.js 环境- 代表性实践 [requirejs](http://requirejs.org/)、[curl.js](https://github.com/cujojs/curl)- CMD(Common Module Definition)- CMD 规范整合了 CommonJS 和 AMD 规范的特点- CMD 规范专门用于**浏览器端**,模块的加载是异步的,模块使用时才会加载执行- 代表性实践:[sea.js](https://github.com/seajs/seajs)- ES6 Module- 语言层面上实现模块化- 需转换成 ES5 实现- Module in CSS- **@import **语句<a name="EK6Qq"></a>## 手写模块管理引擎注意:不可以在 node.js 环境下运行,因为 node.js 内置了 module 变量声明,会冲突。```javascript/*** 简易的模块管理引擎* 同步执行*/const module = (function () {// 模块容器const moduleList = {}/*** 定义模块* @param {String} name 模块名称* @param {Array} modulesName 依赖模块名称* @param {Function} action 模块执行函数**/function define(name, modulesName, action) {const modules = modulesName.map((name, i) => moduleList[name])moduleList[name] = action.apply(null, modules)}return { define }})()// 下面都是在使用模块管理/*** 声明一个找最大值的模块* 参数一:模块名称* 参数二:该模块依赖的其他模块* 参数三:该模块的执行函数*/module.define('findMax', [], function () {return {max(arr) {let res = 0arr.forEach(item => res = Math.max(res, item))return res}}})/*** 声明 lesson 一个模块,它依赖于找最大值的模块*/module.define('lesson', ['findMax'], function (konsoue) {let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]const max = konsoue.max(data)console.log(max);return data})/*** a 模块,我们用它修改 lesson 模块的值*/module.define('a', ['lesson'], function (lesson) {lesson[0] = 4})/*** b 模块,由于我们在 a 修改了 lesson 模块的值* 在 b 模块,访问 lesson 模块的值是已经被改变的了* 也就是说,各个模块,引用的同一个模块,确实是单例模式*/module.define('b', ['lesson'], function (lesson) {console.log(lesson);})
