应用场景又称发布-订阅模式,指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
在 Javascript 中,观察者模式最主要是应用在事件模型中:
事件模型可以分为两种,首先是原生的 Dom 事件,比如 click,这就是观察者模式的应用,相信大家一定使用过,在此就不再赘述。
其次是自定义事件,随着Vue、Angular等框架的流行,自定义事件也一定不会陌生,我们可以自己写一个自定义事件,来更好的理解观察者模式。
比如,有个购物车的功能,当点击增加或减少商品数量的按钮时,其相对应的数值和价格也会改变。
首先,我们创建一个观察者对象的基本模型:一个缓存列表,和三个方法,分别为订阅方法、发布方法以及取消方法。
const event = function () {
// 缓存列表
const _list = {};
return {
// 订阅方法
listen() {},
// 发布方法
dispatch() {},
// 取消方法
remove() {},
};
};
接下来,就是实现这三个方法。
订阅方法:
// 参数 type:自定义事件名称
// 参数 fn:与 type 相对应的处理方法
listen(type, fn) {
// 如果缓存列表中没有该事件,则注册一个
if (Object.is(_list[type], undefined)) {
_list[type] = [];
}
// 如果缓存列表中有该事件,则把处理方法保存到队列中
_list[type].push(fn);
}
发布方法:
// 参数 type:自定义事件名称
// 参数 args:函数参数
dispatch(type, ...args) {
// 如果缓存列表中没有该事件或者该事件没有可执行的方法,则退出
if (!_list[type] || _list[type].length === 0) {
return false;
}
// 否则依次执行该事件的处理方法
for (let fn of _list[type]) {
fn(...args);
}
}
取消方法:
// 参数 type:自定义事件名称
// 参数 fn:与 type 相对应的处理方法
remove(type, fn) {
// 如果缓存列表中有该事件,并且该事件有可执行的方法,则进行以下操作
if (Array.isArray(_list[type]) && _list[type].length > 0) {
// 如果没有指定某个处理方法,则全部清空
if (!fn) {
_list[type] = [];
} else {
// 如果指定了取消某个处理方法,则相应删除
_list[type] = _list[type].filter((v) => {
return v !== fn;
});
}
}
}
最后,我们去实现购物车的功能:
例子:
观察者模式的意义
台灯数量:1
价格:50
看了上面的例子,很多人会觉得,本来简单的功能,使用观察者模式反而变得复杂,意义何在?
其实,观察者模式的意义可以从两个方面体现出来:
- 在 Javascript 开发中,观察者模式被广泛应用在异步编程中。当我们通过 Ajax 和后台交互时,想在交互完成之后对数据做一些处理,那我们可以订阅一个事件,然后在请求完成之后发布这个事件。
- 观察者模式起到了松耦合的作用,发布者与订阅者之间可以相互通信,但又不会彼此影响,只要事件名称没有变化,就可以自由地改变它们。
如有错误,欢迎指正,本人不胜感激。



