代理模式
解释:这种模式的套路就只有一个—— A 不能直接访问 B,A 需要借助一个帮手来访问 B,这个帮手就是代理器。需要代理器出面解决的问题,就是代理模式发光发热的应用场景。
常见的四种代理模式:事件代理、虚拟代理、缓存代理、保护代理
事件代理
父元素绑定的click就是常见的事件代理 ```javascript e.preventDefault() // 阻止事件默认行为,比如A标签跳转,submit有提交行为
parent.addEventListener(‘click’, function(e) {
e.preventDefault()
// return false也等同于阻止事件的默认行为
alert(我是${aNodes[i].innerText}
)
})
<a name="MzakL"></a>
### 虚拟代理
1. 看小册文章回顾
1. 解偶函数,帮助函数实现单一原则
<a name="cE3Ux"></a>
### 缓存代理
1. 对于大数量计算场景下,缓存之前的计算结果

<a name="Lpiu7"></a>
### 保护代理
1. 依旧是通过Proxy代理对象来进行操作层面的拦截
<a name="GqON4"></a>
## 观察者模式
1. 解释:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新
1. 观察者模式也称为“发布-订阅者模式”,这两者只有轻微的区别
1. 这个模式的两个核心角色:发布者-订阅者(Vue的数据双向绑定也是这个模式的实现综合案例)
1. 实现一个EventBus
```javascript
// 实现一个EventBus
class EventBus {
constructor() {
// 用来存储事件与回调之间的关系
this.handlerMap = {}
}
on (eventName, cb) {
// 先检查目标事件有没有对应的函数队列
if (!this.handlerMap[eventName]) {
this.handlerMap[eventName] = []
}
this.handlerMap[eventName].push(cb)
}
emit (eventName, ...args) {
if (this.handlerMap[eventName]) {
let handler = this.handlerMap[eventName]
handler.forEach(cb => {
cb(...args)
})
}
}
// 移除某个事件回调里的指定事件
off (eventName, cb) {
let handler = this.handlerMap[eventName]
let index = handler.indexOf(cb)
if (index !== -1) {
handler.split(index, 1)
}
}
// 监听事件,但只触发一次
once (eventName, cb) {
const wrapper = (...args) => {
cb(...args)
this.off(eventName, wrapper)
}
this.on(eventName, wrapper)
}
}
export default EventBus
总结:观察者模式和发布-订阅者模式的区别
- 观察者模式没有中间人作为通信,相当于被观察者与观察者进行直接联系通信
- 发布-订阅者模式有一个中间人作为事件中心,由中间人来进行连接发布者与订阅者双方
- 什么时候使用观察者模式或者发布-订阅者模式
- 当两者有耦合的时候可以使用观察者模式
- 当两者耦合性不强时,只是单纯的为了数据通信则使用发布-订阅者模式
迭代器模式
- 解决不同数据结构的统一迭代方式
```javascript
// 自定义迭代器模式
function iterator(args) {
let length = args.length
let index = 0
return {
next() {
let done = index >= length
let value = !done ? args[index++] : undefined
return {
} } } }done,
value
let arr = iterator([1,2,3]) arr.next() {done: false, value: 1} arr.next() {done: false, value: 2} arr.next() {done: false, value: 3} arr.next() {done: true, value: undefined} ```