理解模块化

模块化就是 把复杂的系统分解到多个模块以方便编码
过去代码组织方式,会出现的问题:

  • 命名空间冲突
  • 无法合理地管理项目依赖和版本
  • 无法方便控制依赖的加载顺序
  • 项目体积变大后难以维护

模块化的发展

函数即模块

不同的函数声明,就是一个模块。
缺点:

  1. 污染全局变量,可能与其他模块发生变量名冲突
  2. 模块成员之间依赖关系,难以直接看出来 ```javascript function getUserList() {}

function updateUserName() {}

  1. <a name="pbw7B"></a>
  2. ## 对象即模块
  3. 为了解决污染全局变量的问题,可以把模块写成一个对象,所有的模块成员都放到这个对象里面。<br />优点:
  4. 1. 减少全局的变量数目
  5. 2. 一定程度上,避免了变量名冲突
  6. 缺点:
  7. 1. 对象会暴露所有模块成员,内部状态可被外部改写。(模块成员是非私有的)
  8. ```javascript
  9. var todo = {
  10. list: [],
  11. add: function() {},
  12. delete: function() {},
  13. }
  14. var user = {
  15. list: [],
  16. add: function() {},
  17. delete: function() {},
  18. }

立即执行函数(IIFE)

利用 IIFE 创建闭包,保存私有变量,只暴露给外部对应可访问的权限。
优点:

  1. 避免变量名冲突
  2. 拥有私有变量

缺点:

  1. 依赖情况依然不清晰
    1. var todo = (function () {
    2. const list = []
    3. return {
    4. add: function (item) {
    5. list.push(item)
    6. },
    7. delete: function (index) { },
    8. get: function (index) { }
    9. }
    10. })()

    IIFE 增强版(引入依赖)

    IIFE 增强版:引入依赖
  • 这就是现代模块实现的基石; ```javascript var _fetch = (function () { return function ({ method, url, data, callback }) { return new Promise((resolve, reject) => {
    1. const XHR = new XMLHttpRequest();
    2. XHR.open(method, url)
    3. XHR.onload = function () {
    4. resolve(XHR.responseText)
    5. callback && callback(XHR.responseText)
    6. }
    7. 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 })

  1. <a name="dtgLu"></a>
  2. # 模块化方案
  3. 在**模块化编程**中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为 **模块**。<br />每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。<br />精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
  4. - CommonJS
  5. - **同步加载** 依赖的模块
  6. - 可复用于 Node.js 环境 ,例如做同构应用
  7. - 成熟的第三方模块社区
  8. - 无法直接运行于浏览器环境,必须通过工具转换为标准的 ES5
  9. - AMD (Asynchronous Module Definition)
  10. - **异步加载** 依赖的模块
  11. - **并行** 加载多个模块
  12. - 可在不转换代码的情况下直接在 **浏览器** 运行
  13. - 可运行在浏览器和 Node.js 环境
  14. - 代表性实践 [requirejs](http://requirejs.org/)、[curl.js](https://github.com/cujojs/curl)
  15. - CMD(Common Module Definition)
  16. - CMD 规范整合了 CommonJS 和 AMD 规范的特点
  17. - CMD 规范专门用于**浏览器端**,模块的加载是异步的,模块使用时才会加载执行
  18. - 代表性实践:[sea.js](https://github.com/seajs/seajs)
  19. - ES6 Module
  20. - 语言层面上实现模块化
  21. - 需转换成 ES5 实现
  22. - Module in CSS
  23. - **@import **语句
  24. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1174243/1647584418885-a201be8e-5a43-4f78-8598-9d6c32ed4f56.png#clientId=u5ee63d15-2b19-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ueae51822&margin=%5Bobject%20Object%5D&name=image.png&originHeight=569&originWidth=720&originalType=url&ratio=1&rotation=0&showTitle=false&size=170462&status=done&style=none&taskId=ucab38ad4-f9f6-47bd-b99f-d2b3020334d&title=)
  25. <a name="EK6Qq"></a>
  26. ## 手写模块管理引擎
  27. 注意:不可以在 node.js 环境下运行,因为 node.js 内置了 module 变量声明,会冲突。
  28. ```javascript
  29. /**
  30. * 简易的模块管理引擎
  31. * 同步执行
  32. */
  33. const module = (function () {
  34. // 模块容器
  35. const moduleList = {}
  36. /**
  37. * 定义模块
  38. * @param {String} name 模块名称
  39. * @param {Array} modulesName 依赖模块名称
  40. * @param {Function} action 模块执行函数
  41. *
  42. */
  43. function define(name, modulesName, action) {
  44. const modules = modulesName.map((name, i) => moduleList[name])
  45. moduleList[name] = action.apply(null, modules)
  46. }
  47. return { define }
  48. })()
  49. // 下面都是在使用模块管理
  50. /**
  51. * 声明一个找最大值的模块
  52. * 参数一:模块名称
  53. * 参数二:该模块依赖的其他模块
  54. * 参数三:该模块的执行函数
  55. */
  56. module.define('findMax', [], function () {
  57. return {
  58. max(arr) {
  59. let res = 0
  60. arr.forEach(item => res = Math.max(res, item))
  61. return res
  62. }
  63. }
  64. })
  65. /**
  66. * 声明 lesson 一个模块,它依赖于找最大值的模块
  67. */
  68. module.define('lesson', ['findMax'], function (konsoue) {
  69. let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  70. const max = konsoue.max(data)
  71. console.log(max);
  72. return data
  73. })
  74. /**
  75. * a 模块,我们用它修改 lesson 模块的值
  76. */
  77. module.define('a', ['lesson'], function (lesson) {
  78. lesson[0] = 4
  79. })
  80. /**
  81. * b 模块,由于我们在 a 修改了 lesson 模块的值
  82. * 在 b 模块,访问 lesson 模块的值是已经被改变的了
  83. * 也就是说,各个模块,引用的同一个模块,确实是单例模式
  84. */
  85. module.define('b', ['lesson'], function (lesson) {
  86. console.log(lesson);
  87. })