模块化开发 - Zikzin/Angular.js-study GitHub Wiki

一、模块化开发介绍(Modularization)

1、什么是模块化开发

  • 1、将软件产品看作为一系列功能模块的组合。
  • 2、通过特定的方式实现软件所需模块的划分、管理、加载。

2、为什么要有模块化开发

  • 1、便于协同:你不是一个人在战斗。
  • 2、代码复用
  • 3、解决问题:(可以解决痛点的东西才是好东西,比如ng.js可以解决复杂的dom操作。)

3、实现模块化的推演

(1)全局函数方式约定模块

  • 1、案例:02-evolution文件夹

    • 早期开发过程中就是将重复的代码封装到函数中,再将一系列的函数放到一个文件中,称之为模块。
    • 这只是约定的形式定义的模块,存在命名冲突,可维护性也不高。
    • 仅仅从代码角度来说:没有任何模块的概念。
  • 2、分页实现

    • 案例插件:http://esimakin.github.io/twbs-pagination/
    • 可以用实际数据帮助理清逻辑
    • innerHTML 比 appendChild() 效率高:innerHTML是一次dom操作,appendChild()是多次dom操作,会导致dom上多次重复。
    • classList对象用于给dom元素新增或删除它的类名的那个属性。
    • 学习时候,可以参考其他语言的逻辑,然后用js实现。

(2)封装对象的方式

  • 从代码层面就已经有了模块的感觉。
  • 缺点:还是污染全局(不是问题)。
  • 传统编程语言中的命名空间的概念(math.calculator.add();)。
  • 高内聚,低耦合:模块内部相关性强,模块之间没有过多相互牵连。
  • 但这样还是不够好:因为没有私有空间。

(3)封装单独的私有空间

  • 函数包装一个独立的作用域(自执行函数)
  • 私有的转换逻辑
  • 返回值的方式得到模块的公共成员(return{ add:add,})
  • 比如注册方法中可能会记录日志
  • 优势在于:可以有选择的对外暴露自身成员
  • 私有成员的作用:1、将一个成员私有化。 2、抽象公共方法(其他成员中都会用到的)。

(4)模块的扩展和维护

  • 给自执行函数传参数。
  • 便于庞大模块的子模块划分。
  • 开闭原则,对新增开放,对修改关闭。

(5)第三方依赖管理

  • 对于模块的依赖通过自执行函数传参数。
  • 依赖抽象。
  • 比如jQuery换zepto。
  • 原则:高内聚,低耦合。

4、在什么场景下使用模块化开发

  • 业务复杂。
  • 重用逻辑非常多。
  • 扩展性要求较高。

二、三个规范

-(本身没API,或者使用,你实现我定义的标准,就可以说是实现了这个规范。)

1、CommonJS

(1)服务器端规范(文件都是在本地,而AMD和CMD都是在浏览器端)

  • 服务端js模块化编码规范
  • require
  • exports

(2)Node.js

2、AMD

(1)异步模块定义

(2)推崇依赖前置

(3)浏览器端规范

(4)RequireJS

3、CMD(国内)

(1)通用模块定义

(2)推崇依赖就近

(3)SeaJS(CMD的文档看起来跟API一样,CMD是在seajs中体现的,可以理解为CMD在seajs中实现了,也就是seajs一个人实现了CMD。)

三、实现

1、RequireJS 使用的是AMD规范

2、SeaJS 使用的是CMD规范(而且是作者自己定义的。)(阿里巴巴前端架构师玉伯)

使用步骤

  • (1)引包
  • (2)定义一个模块如main.js(通过define方式并将模块exports暴露出去):在Seajs中模块的引入需要相对路径完整写法,或者使用网站根目录(启用网站服务器时候)
  • (3)引用模块(页面的行内脚本中通过seajs.use('path',fn)的方式使用模块):方便我们模块化,解决了命名冲突(因为文件名不会重复),文件依赖的问题。
  • (4)回调函数的参数传过来的就是模块中导出的成员对象。

定义一个模块

  • define
define(function(require, exports, module) {
  exports.add = function(a, b) {
    return a + b;
  };
});

使用一个模块(两种方式)

  • 1、seajs.use

    • 一般用于入口模块
    • 一般只会使用一次(入口是单一的。)
  • 2、require

    • 模块与模块之间

导出成员的方式

  • (1)module.exports(导出一个成员、一个对象的时候,是一个整体)(module指的是模块信息,不只是exports)
  • (2)exports.xxx (导出部分成员,工具类、方法)
  • (3)return
  • 三种方式的优先级 return > module.exports > exports (一般很少用return)

异步加载模块

  • 默认require的效果是同步的,会阻塞代码的执行,造成界面卡顿
  • require.async();
require.async('path',function(module) {

});

使用第三方依赖(jQuery)

  • 由于CMD是国产货,jquery默认不支持(jQuery支持了AMD,从源码可看出)
  • 改造(直接在jQuery.js中)
// 适配CMD
if (typeof define === "function" && !define.amd) {
  // 当前有define函数,并且不是AMD的情况
  // jquery在新版本中如果使用AMD或CMD方式,不会去往全局挂载jquery对象(noConflict(true))
  define(function() {
    return jQuery.noConflict(true);
  });
}

Seajs配置

  • js中引入模块时,可能模块的层级会陷得比较深,为提高开发效率和可维护性。对变化点进行封装。
  • 如:<script> seajs.config({ alias: { // 变化点封装 calc: './modules/calc.js', } }); seajs.use('calc'); </script>
  • 配置
  • 变化点封装
  • seajs.config
    • base
    • alias 别名设置(对象)

使用案例

  • Tab标签页
⚠️ **GitHub.com Fallback** ⚠️