代理模式
解释:这种模式的套路就只有一个—— 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// 实现一个EventBusclass 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} ```
