MVC

MVC是什么?

一种设计模式,它的设计思路是将模块分成三个对象,分别是M、V、C:

  • M-Model(数据模型):负责操作所有数据;
  • V-view(视图):负责所有UI界面的事情;
  • C-Controller(控制器):负责操作M、V以及其他,即业务逻辑;

MVC解决了什么问题?

减少代码的重复及冗余。

如何实现mvc式代码?

Model

  1. let m = {
  2. data: { '程序需要操作的数据或信息' },
  3. create(){ '增数据' },
  4. delete(){ '删数据' },
  5. update(data) {
  6. //新数据替换旧数据
  7. Object.assign(m.data, data)
  8. //eventBus触发'myEvent'自定义事件
  9. eventBus.trigger('myEvent')
  10. },
  11. get(){ '获取数据' }
  12. }

View

  1. let v = {
  2. el: '被操作的元素节点',
  3. html: `<div>要添加到el的内容</div>`
  4. init(){'页面的初始化'},
  5. render(data){ '渲染页面' }
  6. }

Contorller

  1. let c = {
  2. init(){
  3. // 初始化 v
  4. v.init()
  5. // v 不关心数据的变化,所以由c传入数据进行渲染
  6. v.render(data)
  7. c.autoBindEvents()
  8. // 当eventBus触发'myEvent'自定义事件时进行渲染操作
  9. eventBus.on('myEvent', () => { v.render(data) })
  10. },
  11. events:{ '会被触发的事件以哈希表方式记录' },
  12. autoBindEvents() { '事件绑定' }
  13. }

完整代码

EventBus

mvc式编写代码可以减少代码重复,而EventBus是其中一个帮手。

可以想象,如果上面的代码没有eventBus,那么在更新数据的时候,c还需要手动调用一下v.render()方法,这多麻烦,如果代码量不大还好,要渲染的地方多了,就非常难受了。

那EventBus到底是什么呢?用DOM事件或jQuery的事件监听的时候,是不是非常像EventBus呢?我们给监听函数on或addEventListener提供一个要被响应的事件和响应函数,等事件被响应的时候响应函数被执行,但这不仅是EventBus,而是一种更为高级的实现-“订阅发布模式”。关于“订阅发布模式”这里就不做展开了。结论就是EventBus是自定义事件绑定与触发的机制,通过一个可绑定事件的对象来实现这个功能。

用最简单的方式理解EventBus:

  1. on:监听自定义事件,绑定事件响应函数;
  2. trigger:在某个地方触发自定义事件。

enentBus的函数一般有:

  1. on(事件的绑定)
  1. // 事件列表对象
  2. const evetList = {}
  3. function on(eventName,callback) {
  4. if(!(eventName in eventList)) {
  5. // 事件没有记录过,则为这个事件创建一个新的通知列表
  6. eventList[EventName] = []
  7. }
  8. // 将响应函数callback放到eventName的通知列表中,等待被触发
  9. eventList[EventName].push(callback)
  10. }
  1. emit/trigger(事件的触发)
  1. const eventList = {}
  2. const trigger = (eventName,params)=>{
  3. // 找到与eventName对应的通知列表,将params传给通知列表内的每个响应函数
  4. if(eventList[eventName]){
  5. let arr = eventList[eventName];
  6. arr.forEach(callback => {
  7. callback(params)
  8. })
  9. }
  10. }
  1. off(事件的解绑)
  1. const eventList = {}
  2. const off = (eventName,callback) => {
  3. if(eventList[eventName]) {
  4. let index = eventList[eventName].indexof(callback)
  5. eventList[eventName].splice(index,1)
  6. }
  7. }

表驱动编程

先说结论:表驱动编程是一种编程方法,用来消除代码中频繁的if elseswitch case。不仅如此,这种编程方式可以延伸其他地方,比如DOM的事件绑定,多个button的click事件也可以通过表驱动的方式绑定。

和mvc一样,表驱动编程也是用来减少代码冗余的,它是对重复事情的精简。

可以粗暴的理解为它类似数据库表,这样在代码的编写过程中就可以实现数据和逻辑的分离了。

什么时候可以用到表驱动?

对多个数据有相同处理逻辑的时候就可以用了,此时将数据抽离出来形成“表”,这个表可以是数组、hash表等数据结构。

举个栗子:

  1. let arr = [1,2,3,4,5]
  2. // 打印输出arr的每个元素内容
  3. // 两种处理方式
  4. // 方式一:
  5. console.log(arr[0])
  6. console.log(arr[1])
  7. console.log(arr[2])
  8. console.log(arr[3])
  9. console.log(arr[4])
  10. // 方式二:
  11. arr.forEach(item => {
  12. console.log(item)
  13. })

表驱动编程的好处

  1. 减少代码冗余;
  2. 数据与逻辑分离,数据的增加不会造成逻辑代码的增加
  3. 方便维护代码

模块化

为什么要模块化

  • 可以避免命名冲突
  • 灵活架构,每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。
  • 提高复用性和可维护性

比如说将代码重构为mvc式,m、v、c也是模块,首先模块化可以让文件更有组织,哪个模块出了问题就去哪个模块解决问题,其次是用模块的时候我们不用关心模块内的具体实现,使用模块暴露出的接口就可以了。

模块化的规范

  1. RequireJS模块:RequireJS遵循的是AMD规范。AMD规范是异步加载,依赖前置,特点是准备充分,但加载会较慢。使用define()定义模块,require()加载模块。
  2. SeaJS模块:SeaJS遵循的是CMD规范。CMD规范也会异步加载,不同的是CMD依赖就近,特点是首次加载很快。CMD规范也是使用define()定义模块,require()加载模块。但和AMD规范思想不同,写法也不同。
  3. CommonJS:CommonJS规范使用require加载模块,module.exports导出模块,module可省略,但不推荐。特点是加载模块顺序按照词法解析的顺序加载,是同步加载的。
  4. ES6模块:ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系。使用import和export来导入导出,ES6还提供了一个default,用来提供默认的export。特点是加载模块存储的是值的引用,所以全局只有一份;加载模块也是异步的。ES6的module吸收了CommoneJS和AMD两者的优点,兼容两标准的规范。