目录
1、什么是观察者模式
观察者模式(Observer) 通常又被称为发布-订阅者模式或消息机制, 它定义了对象间的一种一对多的依赖关系, 只要当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新, 解决了主体对象与观察者之间功能的耦合, 即一个对象状态改变给其他对象通知的问题。
下面这段代码就是一种发布-订阅模式:
document.querySelector('#btn').addEventListener('click',function () { alert('You click this btn'); }, false)
除了我们常见的 DOM 事件绑定外,观察者模式应用的范围还有很多~
比如比较当下热门 vue 框架,里面不少地方都涉及到了观察者模式,比如:
数据的双向绑定
利用Object.defineProperty()对数据进行劫持, 设置一个监听器Observer,用来监听所有属性, 如果属性上发上变化了,就需要告诉订阅者Watcher去更新数据, 最后指令解析器Compile解析对应的指令, 进而会执行对应的更新函数,从而更新视图,实现了双向绑定~
子组件与父组件通信
Vue中我们通过props完成父组件向子组件传递数据, 子组件与父组件通信我们通过自定义事件即$on、$emit来实现, 其实也就是通过$emit来发布消息,并对订阅者$on做统一处理~
2、创建一个观察者
首先我们需要创建一个观察者对象,它包含一个消息容器和三个方法,分别是订阅消息方法on,取消订阅消息方法off,发送订阅消息publish。
const Observe = (function() { // 防止消息队列暴露而被篡改,将消息容器设置为私有变量 let __message = {}; return { // 注册消息接口 on: function(type, fn) { // 如果此消息不存在,创建一个该消息类型 if (typeof __message[type] === 'undefined') { // 将执行方法推入该消息对应的执行队列中 __message[type] = [fn]; } else { // 如果此消息存在,直接将执行方法推入该消息对应的执行队列中 __message[type].push(fn); } }, // 发布消息接口 publish: function(type, args) { // 如果该消息没有注册,直接返回 if (!__message[type]) return; // 定义消息信息 const events = { type, // 消息类型 args: args || {} // 参数 } // 遍历执行函数 for (let i = 0, len = __message[type].length; i < len; i++) { // 依次执行注册消息对应的方法 __message[type][i].call(this, events) } }, // 移除消息接口 off: function(type, fn) { // 如果消息执行队列存在 if (__message[type] instanceof Array) { // 从最后一条依次遍历(之所以从最后一个开始遍历,是因为下面会用到splice) for (let i = __message[type].length - 1; i >= 0; i--) { // 如果存在该执行函数则移除相应的动作 __message[type][i] === fn && __message[type].splice(i, 1); } } } } })();
使用:
//订阅消息 Observe.on('say', function (data) { console.log(data.args.text); }) Observe.on('success',function () { console.log('success') }); //发布消息 Observe.publish('say', { text : 'hello world' } ) Observe.publish('success');
我们在消息类型为say、success的消息中注册了两个方法,其中有一个接受参数,另一个不需要参数, 然后通过publish发布say和success消息,结果跟我们预期的一样, 控制台输出了 hello world 以及 success ~