一、 MVC 设计模式
1. 设计模式
- 设计模式,是通用代码(组织方式)的一种统称
2. MVC 是什么
- MVC 是三个单词的首字母缩写,他们分别是 Model(模型)、View(视图)、Controller(控制器)
- MVC 认为,程序无论是简单还是复杂,从结构上看都能分为三层:
- 最下层,核心的的”数据层“(Model):数据保存,用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法
- 最上层,面向用户的”视图层“(View):用户界面,它是提供给用户的界面,描绘的是 model 的当前状态
- 中间层,”控制层“(Controller):业务逻辑,它处理用户的行为和数据 model 上的改变。负责根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终结果
- 这三层紧密联系在一起,但又是互相独立的,每一层内部的变化不影响其他层。每一层都对外提供接口供调用。这样一来,软件就可以实现模块化,修改外观或者变更数据都不用修改其他层,大大方便了维护和升级,提高灵活性和复用性
二、MVC 实例
比如以一个实现加减乘除的简易计算机为例
1. Model 数据模型
- 定义并封装数据以及数据的处理方法
let Model={
data:{}, // 数据源
create:{}, // 增加数据
delete:{}, //删除数据
update(data){}, // 更新数据
get:{} // 获取数据
}
2. View 视图
- 定义和封装渲染到页面的元素和渲染方法
let View={
el, // 要渲染的元素
html, // 要显示在页面上的渲染内容
init(){
v.el // 初始化需要渲染的元素
},
render(){} // 渲染页面
}
3. Controller 控制器
- 根据用户的行为,更新数据和视图
let Controller={
init(){}, // 初始化渲染页面
events: {}, // 事件
// 点击事件的实现
add(){},
minus() {},
mul(){},
div(){},
autoBindEvents(){} // 绑定事件
}
三、 发布/订阅
JS 中事件完全可以理解成“信号”,如果存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”一个信号,其他任务可以向信号中心“订阅”这个信号,从而知道什么时候自己可以开始执行,这就叫做”发布/订阅模式”,又称“观察者模式”
// f2 向信号中心 jQuery 订阅 done 信号
jQuery.subscribe('done', f2)
// f1 执行完成后,向信号中心 jQuery 发布 done 信号,从而引发 f2 的执行
function f1() {
setTimeout(function () {
// ...
jQuery.publish('done')
}, 1000)
}
// f2 完成执行后,可以取消订阅
jQuery.unsubscribe('done', f2)
这种方法的性质与“事件监听”类似,但是明显优于后者。因为可以通过查看“消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行
四、 EventBus
EventBus,也称为事件总线,在 JS 是一种对象或组件的通信方式,是发布订阅模式的一种具体实现
可以利用 EventBus 原生的on()
、off()
、trigger()/emit()
API 来发布订阅、取消订阅、触发
如何理解 EventBus 呢
- 用一个十分浅显的例子,Bus 即公交车,城市中的公交车的是怎么运作的呢?
公交车会在城市中按照既定的路线一遍遍的循环。乘客上车之后会跟公交车司机说一下”我在第二站,下车“,于是等公交车到了第二站后,会提醒乘客”第二站到了,请下车“,如果乘客中途改变了注意也会告诉司机”我第二站不下车了,后面的站再下车“。 - EventBus 是怎么运行的呢?
相应的,EventBus 对象会在 JS 线程中一遍一遍的循环。它是一个订阅中心,比如你向起订阅一个点击事件EventBus.on('click')
,当事件触发时 EventBus 会执行你添加的事件监听函数EventBus.emit('click')
,如果想取消订阅可以EventBus.off('click')
来取消订阅 - 事实上,我们在使用 JS 绑定事件监听函数,都是在使用发布订阅模式
五、表驱动编程
我们在编程过程中,免不了会遇到需要判断多种条件的情况,这种时候如果使用 if...else、switch 语句,写出的代码就会出现可读性较差甚至出现错误,如果我们使用表驱动编程的方式就会是代码可读性增强并且不容易出错。
- 浅显易懂的例子
const day = new Date().getDay()
let day_zh;
if(day === 0){
day_zh = '星期日'
}else if(day === 1) {
day_zh = '星期一'
}
...
else{
day_zh = '星期六'
}
// 或者 用 switch case
switch(day) {
case 0:
day_zh = '星期日'
break;
case 1:
day_zh = '星期一'
break;
...
}
// 使用表驱动的方式
const week = ['星期日', '星期一',..., '星期六']
const day = new Date().getDay(
const day_zh = week[day]
六、模块化
- 模块化就是把功能相对独立的代码从一大段代码里封装成一个个短小精悍的模块
- 每个模块之间相对独立,每个模块的修改不会影响其他模块的功能,甚至不同模块之间使用不同的技术实现也不会带来影响
- ES6的语法里使用 Import 和 export 语法来实现 JS 代码的模块化