javascrpt 观察者模式,又称发布-订阅模式或者消息机制。如果看到这几个名称,说的都是一回事。
其实在 javascript 中经常看到这种模式,比如 监听点击事件
// 监听点击事件
document.querySelector('#btn').addEventListener('click',function () {
alert('You click this btn');
})
什么是观察者模式?比如生活中就像是去报社订报纸,你喜欢读什么报就去报社去交钱订阅,当发布了新报纸的时候,报社会向所有订阅了报纸的每一个人发送一份,订阅者就可以接收到。
那 javascript 如何实现观察者模式呢?
从以下几方面考虑:
- 一个调度对象( { key: value } ),key 对应名称,value 对应数组,数组里是订阅者函数
- 一个订阅方法,添加进调度对象
- 一个移除方法,移除调度对象中对应的方法
- 一个只订阅一次的方法,执行之后立刻移除
代码实现如下:
class Event {
constructor() {
// 调度对象
this.events = {}
}
/**
* 注册事件
* @param {string} name 事件名称
* @param {function} fn 执行函数
*/
on(name, fn) {
if (!this.events[name]) {
this.events[name] = []
}
this.events[name].push(fn)
}
/**
* 执行事件
* @param {string} name 事件名称
* @param {...any} args 执行参数
*/
emit(name, ...args) {
if (!this.events[name]) {
return
}
this.events[name].forEach(fn => {
fn.call(this, ...args)
})
}
/**
* 移除事件
* @param {string} name 事件名称
* @param {function} fn 函数名称
*/
off(name, fn) {
if (!this.events[name]) {
return
}
// 如果未传函数名称
if (!fn) {
this.events[name] = null
return
}
const index = this.events[name].indexOf(fn)
this.events[name].splice(index, 1)
}
/**
* 只监听执行一次
* @param {string} name 事件名称
* @param {function} fn 执行函数
*/
once(name, fn) {
// 构建执行一次就移除方法
const only = (...args) => {
fn.call(this, ...args)
this.off(name, only)
}
// 开始监听
this.on(name, only)
}
}
测试代码:
let events = new Event()
events.on('fire', function (name1, name2) {
console.log(name1, name2)
})
events.once('fire1', function (name1, name2) {
console.log('once', name1, name2)
})
setTimeout(() => {
events.emit('fire', '参数1', '参数2')
events.emit('fire1', '参数1', '参数2')
events.emit('fire', '参数1', '参数2')
}, 1000)